From 9f978156827e888055feb3c583f949d28c8cb4d6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Sun, 14 Sep 2025 23:34:58 +0800 Subject: [PATCH 001/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=81=97=E6=BC=8F?= =?UTF-8?q?=E7=9A=84tag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/entity/WallTorchParticleBlockEntity.java | 1 - .../resources/default/configuration/blocks/copper_coil.yml | 2 ++ .../momirealms/craftengine/core/pack/AbstractPackManager.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/WallTorchParticleBlockEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/WallTorchParticleBlockEntity.java index f571661e8..cdf545719 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/WallTorchParticleBlockEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/WallTorchParticleBlockEntity.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.SimpleContext; -import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.HorizontalDirection; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.CEWorld; diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml b/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml index c0fe30805..7edbe4e33 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml @@ -26,6 +26,8 @@ items: is-suffocating: true instrument: basedrum map-color: 15 + tags: + - minecraft:mineable/pickaxe behavior: type: lamp_block states: 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 f053a6102..62898220f 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 @@ -728,7 +728,7 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().info("Validated resource pack in " + (time3 - time2) + "ms"); Path finalPath = resourcePackPath(); Files.createDirectories(finalPath.getParent()); - if (!VersionHelper.PREMIUM) { + if (!VersionHelper.PREMIUM && Config.enableObfuscation()) { Config.instance().setObf(false); this.plugin.logger().warn("Resource pack obfuscation requires Premium Edition."); } From 7363f4c0c7987036439504d932036f888c4694c9 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Mon, 15 Sep 2025 14:44:17 +0800 Subject: [PATCH 002/125] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84=E8=B8=A2=E5=87=BA=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/network/PacketConsumers.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b8671f959..21682150b 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 @@ -2504,7 +2504,7 @@ public class PacketConsumers { if (!user.isUUIDVerified()) { if (Config.strictPlayerUuidValidation()) { TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString()); - user.kick(Component.translatable("disconnect.loginFailed")); + user.kick(Component.translatable("disconnect.loginFailedInfo").arguments(Component.translatable("argument.uuid.invalid"))); return; } if (Config.debugResourcePack()) { From 69bd789a43c3b053cf72cdabc7215646f78daee9 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 16 Sep 2025 21:20:22 +0800 Subject: [PATCH 003/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=BE=B9=E7=BC=98?= =?UTF-8?q?=E5=85=89=E7=85=A7=E4=B8=A2=E5=A4=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/injector/WorldStorageInjector.java | 10 +++----- .../bukkit/world/BukkitWorldManager.java | 25 ++++++++++++++----- gradle.properties | 2 +- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java index 6a79e1032..430683add 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java @@ -313,9 +313,7 @@ public final class WorldStorageInjector { @SuppressWarnings("DuplicatedCode") private static void updateLight(@This InjectedHolder thisObj, Object clientState, Object serverState, int x, int y, int z) { CEWorld world = thisObj.ceChunk().world; - Object blockPos = LocationUtils.toBlockPos(x, y, z); - Object serverWorld = world.world().serverWorld(); - if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(serverState, clientState, serverWorld, blockPos)) { + if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(serverState, clientState)) { SectionPos sectionPos = thisObj.cePos(); List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15); world.sectionLightUpdated(pos); @@ -325,16 +323,14 @@ public final class WorldStorageInjector { @SuppressWarnings("DuplicatedCode") private static void updateLight$complex(@This InjectedHolder thisObj, Object newClientState, Object newServerState, Object oldServerState, int x, int y, int z) { CEWorld world = thisObj.ceChunk().world; - Object blockPos = LocationUtils.toBlockPos(x, y, z); - Object serverWorld = world.world().serverWorld(); // 如果客户端新状态和服务端新状态光照属性不同 - if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(newClientState, newServerState, serverWorld, blockPos)) { + if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(newClientState, newServerState)) { SectionPos sectionPos = thisObj.cePos(); List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15); world.sectionLightUpdated(pos); return; } - if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(newServerState, oldServerState, serverWorld, blockPos)) { + if (FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(newServerState, oldServerState)) { SectionPos sectionPos = thisObj.cePos(); List pos = SectionPosUtils.calculateAffectedRegions((sectionPos.x() << 4) + x, (sectionPos.y() << 4) + y, (sectionPos.z() << 4) + z, 15); world.sectionLightUpdated(pos); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitWorldManager.java index 2a90f6333..9be7ba113 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 @@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.WorldStorageInjector; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; @@ -275,16 +276,19 @@ public class BukkitWorldManager implements WorldManager, Listener { } private void handleChunkLoad(CEWorld ceWorld, Chunk chunk) { - ChunkPos pos = new ChunkPos(chunk.getX(), chunk.getZ()); - if (ceWorld.isChunkLoaded(pos.longKey)) return; + int chunkX = chunk.getX(); + int chunkZ = chunk.getZ(); + ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); + if (ceWorld.isChunkLoaded(chunkPos.longKey)) return; CEChunk ceChunk; try { - ceChunk = ceWorld.worldDataStorage().readChunkAt(ceWorld, pos); + ceChunk = ceWorld.worldDataStorage().readChunkAt(ceWorld, chunkPos); try { CESection[] ceSections = ceChunk.sections(); Object worldServer = FastNMS.INSTANCE.field$CraftChunk$worldServer(chunk); Object chunkSource = FastNMS.INSTANCE.method$ServerLevel$getChunkSource(worldServer); - Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunk.getX(), chunk.getZ()); + Object lightEngine = FastNMS.INSTANCE.method$ChunkSource$getLightEngine(chunkSource); + Object levelChunk = FastNMS.INSTANCE.method$ServerChunkCache$getChunkAtIfLoadedMainThread(chunkSource, chunkX, chunkZ); Object[] sections = FastNMS.INSTANCE.method$ChunkAccess$getSections(levelChunk); synchronized (sections) { for (int i = 0; i < ceSections.length; i++) { @@ -339,13 +343,22 @@ public class BukkitWorldManager implements WorldManager, Listener { } } if (Config.restoreCustomBlocks()) { + boolean isEmptyBefore = FastNMS.INSTANCE.method$LevelSection$hasOnlyAir(section); + int sectionY = ceSection.sectionY; + if (isEmptyBefore) { + FastNMS.INSTANCE.method$LightEventListener$updateSectionStatus(lightEngine, FastNMS.INSTANCE.method$SectionPos$of(chunkX, sectionY, chunkZ), false); + } if (!ceSection.statesContainer().isEmpty()) { for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { for (int y = 0; y < 16; y++) { ImmutableBlockState customState = ceSection.getBlockState(x, y, z); if (!customState.isEmpty() && customState.customBlockState() != null) { - FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, customState.customBlockState().literalObject(), false); + Object newState = customState.customBlockState().literalObject(); + Object previous = FastNMS.INSTANCE.method$LevelChunkSection$setBlockState(section, x, y, z, newState, false); + if (newState != previous && FastNMS.INSTANCE.method$LightEngine$hasDifferentLightProperties(newState, previous)) { + FastNMS.INSTANCE.method$ThreadedLevelLightEngine$checkBlock(lightEngine, LocationUtils.toBlockPos(chunkX * 16 + x, sectionY * 16 + y, chunkZ * 16 + z)); + } } } } @@ -353,7 +366,7 @@ public class BukkitWorldManager implements WorldManager, Listener { } } int finalI = i; - WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(pos.x, ceChunk.sectionY(i), pos.z), + WorldStorageInjector.injectLevelChunkSection(section, ceSection, ceChunk, new SectionPos(chunkPos.x, ceChunk.sectionY(i), chunkPos.z), (injected) -> sections[finalI] = injected); } } diff --git a/gradle.properties b/gradle.properties index 69959143c..3a5d0e20e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.87 +nms_helper_version=1.0.89 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1 From 35807d7a214ded8a38eb6b0d8e8c7abfa214a143 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 16 Sep 2025 22:33:02 +0800 Subject: [PATCH 004/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=85=8D=E6=96=B9?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/RecipeEventListener.java | 21 ++++++++++++------- .../item/recipe/AbstractRecipeSerializer.java | 11 ++++++++++ .../recipe/CustomCraftingTableRecipe.java | 16 +++++++++++++- .../core/item/recipe/CustomShapedRecipe.java | 14 +++++++++---- .../item/recipe/CustomShapelessRecipe.java | 13 ++++++++---- gradle.properties | 2 +- 6 files changed, 60 insertions(+), 17 deletions(-) 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 59894f3e4..7d98b15d5 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 @@ -23,6 +23,8 @@ 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.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.util.*; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -619,7 +621,7 @@ public class RecipeEventListener implements Listener { } } - @EventHandler(ignoreCancelled = true) + @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onCraftingFinish(CraftItemEvent event) { if (!Config.enableRecipeSystem()) return; org.bukkit.inventory.Recipe recipe = event.getRecipe(); @@ -634,14 +636,19 @@ public class RecipeEventListener implements Listener { if (!(optionalRecipe.get() instanceof CustomCraftingTableRecipe craftingTableRecipe)) { return; } - if (!craftingTableRecipe.hasVisualResult()) { - return; - } - CraftingInput input = getCraftingInput(inventory); - if (input == null) return; Player player = InventoryUtils.getPlayerFromInventoryEvent(event); BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); - inventory.setResult(craftingTableRecipe.assemble(input, ItemBuildContext.of(serverPlayer))); + if (!craftingTableRecipe.hasVisualResult()) { + CraftingInput input = getCraftingInput(inventory); + inventory.setResult(craftingTableRecipe.assemble(input, ItemBuildContext.of(serverPlayer))); + } + Function[] functions = craftingTableRecipe.craftingFunctions(); + if (functions != null) { + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer); + for (Function function : functions) { + function.run(context); + } + } } private CraftingInput getCraftingInput(CraftingInventory inventory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java index d6a3460f5..8f4632676 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -9,6 +9,9 @@ import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.item.recipe.result.PostProcessor; import net.momirealms.craftengine.core.item.recipe.result.PostProcessors; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; import org.jetbrains.annotations.NotNull; @@ -24,6 +27,14 @@ public abstract class AbstractRecipeSerializer> implement new VanillaRecipeReader1_20_5() : new VanillaRecipeReader1_20(); + @SuppressWarnings("unchecked") + protected Function[] functions(Map arguments) { + Object functions = arguments.get("functions"); + if (functions == null) return null; + List> functionList = ResourceConfigUtils.parseConfigAsList(functions, EventFunctions::fromMap); + return functionList.toArray(new Function[0]); + } + protected boolean showNotification(Map arguments) { return ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("show-notification", true), "show-notification"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java index 655f40ea4..d6cb7b67a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java @@ -4,17 +4,27 @@ 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.result.CustomRecipeResult; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe { protected final CraftingRecipeCategory category; private final CustomRecipeResult visualResult; + private final Function[] craftingFunctions; - protected CustomCraftingTableRecipe(Key id, boolean showNotification, CustomRecipeResult result, @Nullable CustomRecipeResult visualResult, String group, CraftingRecipeCategory category) { + protected CustomCraftingTableRecipe(Key id, + boolean showNotification, + CustomRecipeResult result, + @Nullable CustomRecipeResult visualResult, + String group, + CraftingRecipeCategory category, + Function[] craftingFunctions) { super(id, showNotification, result, group); this.category = category == null ? CraftingRecipeCategory.MISC : category; this.visualResult = visualResult; + this.craftingFunctions = craftingFunctions; } public CraftingRecipeCategory category() { @@ -49,4 +59,8 @@ public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe return super.result.buildItem(context); } } + + public Function[] craftingFunctions() { + return craftingFunctions; + } } 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 40af56a0f..bad93556a 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 @@ -5,6 +5,9 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -24,8 +27,9 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { CustomRecipeResult visualResult, String group, CraftingRecipeCategory category, - Pattern pattern) { - super(id, showNotification, result, visualResult, group, category); + Pattern pattern, + Function[] craftingFunctions) { + super(id, showNotification, result, visualResult, group, category, craftingFunctions); this.pattern = pattern; this.parsedPattern = pattern.parse(); } @@ -169,7 +173,8 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { parseResult(arguments), parseVisualResult(arguments), arguments.containsKey("group") ? arguments.get("group").toString() : null, craftingRecipeCategory(arguments), - new Pattern<>(pattern.toArray(new String[0]), ingredients) + new Pattern<>(pattern.toArray(new String[0]), ingredients), + functions(arguments) ); } @@ -182,7 +187,8 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { null, VANILLA_RECIPE_HELPER.readGroup(json), VANILLA_RECIPE_HELPER.craftingCategory(json), - new Pattern<>(VANILLA_RECIPE_HELPER.craftingShapedPattern(json), ingredients) + new Pattern<>(VANILLA_RECIPE_HELPER.craftingShapedPattern(json), ingredients), + null ); } 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 678c75543..a23c0c4bf 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 @@ -4,6 +4,8 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import org.jetbrains.annotations.NotNull; @@ -23,8 +25,9 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { CustomRecipeResult visualResult, String group, CraftingRecipeCategory category, - List> ingredients) { - super(id, showNotification, result, visualResult, group, category); + List> ingredients, + Function[] craftingFunctions) { + super(id, showNotification, result, visualResult, group, category, craftingFunctions); this.ingredients = ingredients; this.placementInfo = PlacementInfo.create(ingredients); } @@ -88,7 +91,8 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { parseResult(arguments), parseVisualResult(arguments), arguments.containsKey("group") ? arguments.get("group").toString() : null, craftingRecipeCategory(arguments), - ingredients + ingredients, + functions(arguments) ); } @@ -99,7 +103,8 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { parseResult(VANILLA_RECIPE_HELPER.craftingResult(json.getAsJsonObject("result"))), null, VANILLA_RECIPE_HELPER.readGroup(json), VANILLA_RECIPE_HELPER.craftingCategory(json), - VANILLA_RECIPE_HELPER.shapelessIngredients(json.getAsJsonArray("ingredients")).stream().map(this::toIngredient).toList() + VANILLA_RECIPE_HELPER.shapelessIngredients(json.getAsJsonArray("ingredients")).stream().map(this::toIngredient).toList(), + null ); } } diff --git a/gradle.properties b/gradle.properties index 3a5d0e20e..c40afd9f7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63 +project_version=0.0.63.1 config_version=45 lang_version=29 project_group=net.momirealms From 5bfc2be9c9ff41dc6841aed69e7f245c7c3b1ba5 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Tue, 16 Sep 2025 22:48:23 +0800 Subject: [PATCH 005/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=85=8D=E6=96=B9?= =?UTF-8?q?=E7=94=A8=E9=80=94=E5=87=BA=E7=8E=B0trim=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/item/recipe/AbstractRecipeManager.java | 14 ++++++++------ .../core/item/recipe/CustomSmithingTrimRecipe.java | 5 +++++ .../craftengine/core/item/recipe/Recipe.java | 4 ++++ 3 files changed, 17 insertions(+), 6 deletions(-) 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 2e2b739df..670407315 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 @@ -106,12 +106,14 @@ public abstract class AbstractRecipeManager implements RecipeManager { if (recipe instanceof AbstractedFixedResultRecipe fixedResult) { this.byResult.computeIfAbsent(fixedResult.result().item().id(), k -> new ArrayList<>()).add(recipe); } - HashSet usedKeys = new HashSet<>(); - for (Ingredient ingredient : recipe.ingredientsInUse()) { - for (UniqueKey holder : ingredient.items()) { - Key key = holder.key(); - if (usedKeys.add(key)) { - this.byIngredient.computeIfAbsent(key, k -> new ArrayList<>()).add(recipe); + if (recipe.canBeSearchedByIngredients()) { + HashSet usedKeys = new HashSet<>(); + for (Ingredient ingredient : recipe.ingredientsInUse()) { + for (UniqueKey holder : ingredient.items()) { + Key key = holder.key(); + if (usedKeys.add(key)) { + this.byIngredient.computeIfAbsent(key, k -> new ArrayList<>()).add(recipe); + } } } } 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 index a85d30573..1d1195624 100644 --- 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 @@ -103,6 +103,11 @@ public class CustomSmithingTrimRecipe extends AbstractRecipe { return pattern; } + @Override + public boolean canBeSearchedByIngredients() { + return false; + } + @SuppressWarnings({"DuplicatedCode"}) public static class Serializer extends AbstractRecipeSerializer> { 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 db3d2f675..ff5864916 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 @@ -25,4 +25,8 @@ public interface Recipe { default boolean showNotification() { return true; } + + default boolean canBeSearchedByIngredients() { + return true; + } } From f1723df61604d7b608657fbec1eefa55abadad50 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 17 Sep 2025 01:13:59 +0800 Subject: [PATCH 006/125] =?UTF-8?q?fix(sound):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=80=9A=E8=BF=87=E6=B8=B8=E6=88=8F=E4=BA=8B=E4=BB=B6=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E7=9A=84=E6=96=B9=E5=9D=97=E7=A0=B4=E5=9D=8F=E9=9F=B3?= =?UTF-8?q?=E6=95=88=E8=A2=ABremap=E5=90=8E=E6=9C=AA=E8=A1=A5=E5=8C=85?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E6=97=A0=E5=A3=B0=E9=9F=B3=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 23 +++++++++++++++++++ .../craftengine/core/util/RandomUtils.java | 4 ++++ gradle.properties | 2 +- 3 files changed, 28 insertions(+), 1 deletion(-) 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 21682150b..56260a14a 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 @@ -502,6 +502,29 @@ public class PacketConsumers { int state = buf.readInt(); boolean global = buf.readBoolean(); int newState = user.clientModEnabled() ? remapMOD(state) : remap(state); + Object blockState = BlockStateUtils.idToBlockState(newState); + Object block = BlockStateUtils.getBlockOwner(blockState); + if (BukkitBlockManager.instance().isBlockSoundRemoved(block) && !FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) { + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); + Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString()); + Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId); + if (mappedSoundId != null) { + Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty()); + Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); + Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( + mappedBreakSoundHolder, + CoreReflections.instance$SoundSource$BLOCKS, + blockPos.x() + 0.5, + blockPos.y() + 0.5, + blockPos.z() + 0.5, + (FastNMS.INSTANCE.field$SoundType$volume(soundType) + 1.0F) / 2.0F, + FastNMS.INSTANCE.field$SoundType$pitch(soundType) * 0.8F, + RandomUtils.generateRandomLong() + ); + user.sendPacket(packet, true); + } + } if (newState == state) { return; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java index b659d4c28..7904d1776 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/RandomUtils.java @@ -22,6 +22,10 @@ public final class RandomUtils { return ThreadLocalRandom.current().nextBoolean(); } + public static long generateRandomLong() { + return ThreadLocalRandom.current().nextLong(); + } + public static double triangle(double mode, double deviation) { return mode + deviation * (generateRandomDouble(0,1) - generateRandomDouble(0,1)); } diff --git a/gradle.properties b/gradle.properties index c40afd9f7..873f9bbbc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.89 +nms_helper_version=1.0.90 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1 From 5b1c12a3ae13f157015a6d1f4ff0f7631bbb767f Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 17 Sep 2025 01:47:30 +0800 Subject: [PATCH 007/125] =?UTF-8?q?fix(sound):=20=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E5=86=99=E6=B3=95=E4=B8=8D=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=8F=91=E5=A3=B0=E9=9F=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/api/CraftEngineBlocks.java | 32 ++++++++++++++----- .../AbstractCanSurviveBlockBehavior.java | 8 ++--- .../behavior/DoubleHighBlockBehavior.java | 8 ++--- .../behavior/PressurePlateBlockBehavior.java | 8 ++--- 4 files changed, 36 insertions(+), 20 deletions(-) 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 93ec4c025..88fa7042b 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 @@ -188,16 +188,14 @@ public final class CraftEngineBlocks { * @param player player who breaks the block * @param dropLoot whether to drop block loots * @param isMoving is moving - * @param playSound whether to play break sounds - * @param sendParticles whether to send break particles + * @param sendLevelEvent whether to send break particles and sounds * @return success or not */ public static boolean remove(@NotNull Block block, @Nullable Player player, boolean isMoving, boolean dropLoot, - boolean playSound, - boolean sendParticles) { + boolean sendLevelEvent) { ImmutableBlockState state = getCustomBlockState(block); if (state == null || state.isEmpty()) return false; World world = new BukkitWorld(block.getWorld()); @@ -215,16 +213,34 @@ public final class CraftEngineBlocks { world.dropItemNaturally(position, item); } } - if (playSound) { - world.playBlockSound(position, state.settings().sounds().breakSound()); - } - if (sendParticles) { + if (sendLevelEvent) { 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; } + /** + * Removes a block from the world if it's custom + * + * @param block block to remove + * @param player player who breaks the block + * @param dropLoot whether to drop block loots + * @param isMoving is moving + * @param playSound whether to play break sounds + * @param sendParticles whether to send break particles + * @return success or not + */ + @Deprecated + public static boolean remove(@NotNull Block block, + @Nullable Player player, + boolean isMoving, + boolean dropLoot, + boolean playSound, + boolean sendParticles) { + return remove(block, player, dropLoot, isMoving, playSound || sendParticles); + } + /** * Checks if a block is custom * 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 2ab895fe7..6e2ef1443 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 @@ -70,11 +70,11 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio return state; } if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) { - BlockPos pos = LocationUtils.fromBlockPos(blockPos); + // BlockPos pos = LocationUtils.fromBlockPos(blockPos); ImmutableBlockState customState = optionalCustomState.get(); - 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()); + // 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; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java index 14305b479..7cac0ad6d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java @@ -50,10 +50,10 @@ public class DoubleHighBlockBehavior extends BukkitBlockBehavior { 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()); + // 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; } 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 da6eb9d78..3d807c87c 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 @@ -66,10 +66,10 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { return MBlocks.AIR$defaultState; } ImmutableBlockState customState = optionalCustomState.get(); - 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()); + // 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; } From 811523a0c8ff78439877265425ba8079ee3528e4 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 17 Sep 2025 03:06:38 +0800 Subject: [PATCH 008/125] =?UTF-8?q?=E5=AE=8C=E5=96=84=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/ToggleableLampBlockBehavior.java | 2 +- .../craftengine/bukkit/item/recipe/RecipeEventListener.java | 4 ++-- .../resources/default/configuration/blocks/safe_block.yml | 2 ++ .../resources/default/configuration/blocks/table_lamp.yml | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ToggleableLampBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ToggleableLampBlockBehavior.java index 577c167c0..4fbb1b43f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ToggleableLampBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ToggleableLampBlockBehavior.java @@ -91,7 +91,7 @@ public class ToggleableLampBlockBehavior extends BukkitBlockBehavior { public static class Factory implements BlockBehaviorFactory { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - boolean canOpenWithHand = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-open-with-hand", false), "can-open-with-hand"); + boolean canOpenWithHand = ResourceConfigUtils.getAsBoolean(ResourceConfigUtils.get(arguments, "can-open-with-hand", "can-toggle-with-hand"), "can-toggle-with-hand"); Property lit = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("lit"), "warning.config.block.behavior.toggleable_lamp.missing_lit"); Property powered = (Property) (canOpenWithHand ? block.getProperty("powered") : ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.toggleable_lamp.missing_powered")); return new ToggleableLampBlockBehavior(block, lit, powered, canOpenWithHand); 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 7d98b15d5..6120f6855 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 @@ -614,7 +614,7 @@ public class RecipeEventListener implements Listener { if (input == null) return; Player player = InventoryUtils.getPlayerFromInventoryEvent(event); BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); - if (craftingTableRecipe.hasVisualResult()) { + if (craftingTableRecipe.hasVisualResult() && VersionHelper.PREMIUM) { inventory.setResult(craftingTableRecipe.assembleVisual(input, ItemBuildContext.of(serverPlayer))); } else { inventory.setResult(craftingTableRecipe.assemble(input, ItemBuildContext.of(serverPlayer))); @@ -623,7 +623,7 @@ public class RecipeEventListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST) public void onCraftingFinish(CraftItemEvent event) { - if (!Config.enableRecipeSystem()) return; + if (!Config.enableRecipeSystem() || !VersionHelper.PREMIUM) return; org.bukkit.inventory.Recipe recipe = event.getRecipe(); if (!(recipe instanceof CraftingRecipe craftingRecipe)) return; Key recipeId = Key.of(craftingRecipe.getKey().namespace(), craftingRecipe.getKey().value()); diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml index 99d1a28e3..a1349bcbd 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml @@ -22,6 +22,8 @@ items: push-reaction: block instrument: basedrum map-color: 6 + tags: + - minecraft:mineable/pickaxe sounds: break: minecraft:block.stone.break fall: minecraft:block.stone.fall diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml b/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml index 8802410b6..7539c0882 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml @@ -21,9 +21,10 @@ items: replaceable: false is-redstone-conductor: false is-suffocating: false + support-shape: cobweb behaviors: - type: toggleable_lamp_block - can-open-with-hand: true + can-toggle-with-hand: true - type: sturdy_base_block direction: down support-types: From 6faf6ca88bc64f2510d63126b43510f005ce20e1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 17 Sep 2025 04:54:51 +0800 Subject: [PATCH 009/125] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=80=E5=AF=B9?= =?UTF-8?q?=E4=B8=80=E5=88=97=E8=A1=A8=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/PacketConsumers.java | 16 +++++++-- .../core/util/IntIdentityList.java | 35 ++++++++++++++----- .../core/world/chunk/packet/MCSection.java | 6 +++- 3 files changed, 45 insertions(+), 12 deletions(-) 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 21682150b..f0e46f014 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 @@ -87,14 +87,15 @@ import org.jetbrains.annotations.Nullable; import java.nio.charset.StandardCharsets; import java.util.*; import java.util.function.BiConsumer; +import java.util.function.Consumer; public class PacketConsumers { private static BukkitNetworkManager.Handlers[] ADD_ENTITY_HANDLERS; private static int[] BLOCK_STATE_MAPPINGS; private static int[] MOD_BLOCK_STATE_MAPPINGS; private static IntIdentityList SERVER_BLOCK_LIST; - private static IntIdentityList CLIENT_BLOCK_LIST; private static IntIdentityList BIOME_LIST; + private static Consumer> BIOME_MAPPER; public static void initEntities(int registrySize) { ADD_ENTITY_HANDLERS = new BukkitNetworkManager.Handlers[registrySize]; @@ -230,6 +231,16 @@ public class PacketConsumers { }; } + public static void setBiomeMapper(Consumer> mapper) { + BIOME_MAPPER = mapper; + } + + public static void remapBiomes(PalettedContainer biomes) { + if (BIOME_MAPPER != null) { + BIOME_MAPPER.accept(biomes); + } + } + public static void initBlocks(Map map, int registrySize) { int[] newMappings = new int[registrySize]; for (int i = 0; i < registrySize; i++) { @@ -250,7 +261,6 @@ public class PacketConsumers { BLOCK_STATE_MAPPINGS = newMappings; MOD_BLOCK_STATE_MAPPINGS = newMappingsMOD; SERVER_BLOCK_LIST = new IntIdentityList(registrySize); - CLIENT_BLOCK_LIST = new IntIdentityList(BlockStateUtils.vanillaStateSize()); BIOME_LIST = new IntIdentityList(RegistryUtils.currentBiomeRegistrySize()); } @@ -340,6 +350,7 @@ public class PacketConsumers { MCSection mcSection = new MCSection(user.clientBlockList(), SERVER_BLOCK_LIST, BIOME_LIST); mcSection.readPacket(friendlyByteBuf); PalettedContainer container = mcSection.blockStateContainer(); + remapBiomes(mcSection.biomeContainer()); Palette palette = container.data().palette(); if (palette.canRemap()) { palette.remap(PacketConsumers::remapMOD); @@ -363,6 +374,7 @@ public class PacketConsumers { MCSection mcSection = new MCSection(user.clientBlockList(), SERVER_BLOCK_LIST, BIOME_LIST); mcSection.readPacket(friendlyByteBuf); PalettedContainer container = mcSection.blockStateContainer(); + remapBiomes(mcSection.biomeContainer()); Palette palette = container.data().palette(); if (palette.canRemap()) { palette.remap(PacketConsumers::remap); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java b/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java index a60be053e..10df6acd1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/IntIdentityList.java @@ -1,22 +1,16 @@ package net.momirealms.craftengine.core.util; -import it.unimi.dsi.fastutil.ints.IntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Iterator; -import java.util.List; +import java.util.NoSuchElementException; public class IntIdentityList implements IndexedIterable { private final int size; - private final List list; public IntIdentityList(int size) { this.size = size; - list = new IntArrayList(size); - for (int i = 0; i < size; i++) { - list.add(i); - } } @Override @@ -36,6 +30,29 @@ public class IntIdentityList implements IndexedIterable { @Override public @NotNull Iterator iterator() { - return list.iterator(); + return new IntIterator(size); } -} + + private static class IntIterator implements Iterator { + private final int size; + private int current; + + public IntIterator(int size) { + this.size = size; + this.current = 0; + } + + @Override + public boolean hasNext() { + return current < size; + } + + @Override + public Integer next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + return current++; + } + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java index d0931a2ee..9967eb586 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java @@ -9,7 +9,7 @@ public class MCSection { private short nonEmptyBlockCount; private final PalettedContainer serverBlockStateContainer; private final IndexedIterable clientBlockStateList; - private ReadableContainer biomeContainer; + private PalettedContainer biomeContainer; public MCSection(IndexedIterable clientBlockStateList, IndexedIterable serverBlockStateList, IndexedIterable biomeList) { this.serverBlockStateContainer = new PalettedContainer<>(serverBlockStateList, 0, PalettedContainer.PaletteProvider.BLOCK_STATE); @@ -42,4 +42,8 @@ public class MCSection { public PalettedContainer blockStateContainer() { return serverBlockStateContainer; } + + public PalettedContainer biomeContainer() { + return biomeContainer; + } } From 7d3029c193f726e13f7d3136b28646fbca150311 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 17 Sep 2025 18:43:56 +0800 Subject: [PATCH 010/125] =?UTF-8?q?refactor(bukkit):=20=E6=B8=85=E7=90=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/api/CraftEngineBlocks.java | 2 +- .../behavior/AbstractCanSurviveBlockBehavior.java | 10 ++-------- .../bukkit/block/behavior/DoubleHighBlockBehavior.java | 4 ---- .../block/behavior/PressurePlateBlockBehavior.java | 4 ---- 4 files changed, 3 insertions(+), 17 deletions(-) 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 88fa7042b..3fb08edd3 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 @@ -231,7 +231,7 @@ public final class CraftEngineBlocks { * @param sendParticles whether to send break particles * @return success or not */ - @Deprecated + @Deprecated(forRemoval = true) public static boolean remove(@NotNull Block block, @Nullable Player player, boolean isMoving, 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 6e2ef1443..851371fa6 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 @@ -7,7 +7,6 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldEvents; import net.momirealms.craftengine.core.world.WorldPosition; @@ -69,13 +68,8 @@ public abstract class AbstractCanSurviveBlockBehavior extends BukkitBlockBehavio FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, blockPos, thisBlock, this.delay); return state; } - if (!canSurvive(thisBlock, new Object[] {state, level, blockPos}, () -> true)) { - // BlockPos pos = LocationUtils.fromBlockPos(blockPos); - ImmutableBlockState customState = optionalCustomState.get(); - // 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()); + if (!FastNMS.INSTANCE.method$BlockStateBase$canSurvive(state, level, blockPos)) { + FastNMS.INSTANCE.method$LevelAccessor$levelEvent(level, WorldEvents.BLOCK_BREAK_EFFECT, blockPos, optionalCustomState.get().customBlockState().registryId()); return MBlocks.AIR$defaultState; } return state; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java index 7cac0ad6d..7845bddd2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java @@ -50,10 +50,6 @@ public class DoubleHighBlockBehavior extends BukkitBlockBehavior { 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; } 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 3d807c87c..16f852fd2 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 @@ -66,10 +66,6 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { return MBlocks.AIR$defaultState; } ImmutableBlockState customState = optionalCustomState.get(); - // 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; } From ca25e7b7921883cdfd98f22e6b8c43ed127ecd03 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 17 Sep 2025 19:55:52 +0800 Subject: [PATCH 011/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BC=82=E6=AD=A5?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E5=AE=9E=E4=BD=93tick?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../behavior/DoubleHighBlockBehavior.java | 5 +- .../behavior/PressurePlateBlockBehavior.java | 4 +- .../behavior/SimpleParticleBlockBehavior.java | 2 +- .../WallTorchParticleBlockBehavior.java | 2 +- .../item/recipe/RecipeEventListener.java | 25 ++++-- .../plugin/injector/WorldStorageInjector.java | 1 - .../core/block/ImmutableBlockState.java | 11 ++- .../block/behavior/EntityBlockBehavior.java | 6 +- .../item/recipe/AbstractRecipeSerializer.java | 14 ++- .../core/item/recipe/ConditionalRecipe.java | 8 ++ .../recipe/CustomCraftingTableRecipe.java | 15 +++- .../core/item/recipe/CustomShapedRecipe.java | 11 ++- .../item/recipe/CustomShapelessRecipe.java | 10 ++- .../recipe/CustomSmithingTransformRecipe.java | 30 +++++-- .../item/recipe/CustomSmithingTrimRecipe.java | 22 ++++- .../craftengine/core/world/CEWorld.java | 71 +++++++++++---- .../craftengine/core/world/chunk/CEChunk.java | 86 ++++++++++++++----- .../core/world/chunk/packet/MCSection.java | 1 - gradle.properties | 2 +- 19 files changed, 246 insertions(+), 80 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/recipe/ConditionalRecipe.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java index 7845bddd2..723af40e4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java @@ -6,7 +6,6 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect 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; @@ -14,7 +13,9 @@ 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 net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldEvents; import java.util.Map; import java.util.concurrent.Callable; 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 16f852fd2..09c8c920d 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 @@ -8,7 +8,6 @@ import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.EventUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; -import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; @@ -20,7 +19,8 @@ import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.PressurePlateSensitivity; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import net.momirealms.craftengine.core.world.*; +import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.WorldEvents; import org.bukkit.GameEvent; import org.bukkit.util.Vector; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleParticleBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleParticleBlockBehavior.java index d52bda8a4..fa0944580 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleParticleBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleParticleBlockBehavior.java @@ -48,7 +48,7 @@ public class SimpleParticleBlockBehavior extends BukkitBlockBehavior implements } @Override - public BlockEntityTicker createBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType blockEntityType) { + public BlockEntityTicker createAsyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType blockEntityType) { if (this.particles.length == 0) return null; return EntityBlockBehavior.createTickerHelper(SimpleParticleBlockEntity::tick); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallTorchParticleBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallTorchParticleBlockBehavior.java index 84a2d19fb..85888fc1e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallTorchParticleBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/WallTorchParticleBlockBehavior.java @@ -57,7 +57,7 @@ public class WallTorchParticleBlockBehavior extends BukkitBlockBehavior implemen } @Override - public BlockEntityTicker createBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType blockEntityType) { + public BlockEntityTicker createAsyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType blockEntityType) { if (this.particles.length == 0) return null; return EntityBlockBehavior.createTickerHelper(WallTorchParticleBlockEntity::tick); } 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 6120f6855..58392558e 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 @@ -610,14 +610,19 @@ public class RecipeEventListener implements Listener { inventory.setResult(null); return; } - CraftingInput input = getCraftingInput(inventory); - if (input == null) return; Player player = InventoryUtils.getPlayerFromInventoryEvent(event); BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); + ItemBuildContext itemBuildContext = ItemBuildContext.of(serverPlayer); + if (!craftingTableRecipe.canUse(itemBuildContext)) { + inventory.setResult(null); + return; + } + CraftingInput input = getCraftingInput(inventory); + if (input == null) return; if (craftingTableRecipe.hasVisualResult() && VersionHelper.PREMIUM) { - inventory.setResult(craftingTableRecipe.assembleVisual(input, ItemBuildContext.of(serverPlayer))); + inventory.setResult(craftingTableRecipe.assembleVisual(input, itemBuildContext)); } else { - inventory.setResult(craftingTableRecipe.assemble(input, ItemBuildContext.of(serverPlayer))); + inventory.setResult(craftingTableRecipe.assemble(input, itemBuildContext)); } } @@ -638,7 +643,7 @@ public class RecipeEventListener implements Listener { } Player player = InventoryUtils.getPlayerFromInventoryEvent(event); BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); - if (!craftingTableRecipe.hasVisualResult()) { + if (craftingTableRecipe.hasVisualResult()) { CraftingInput input = getCraftingInput(inventory); inventory.setResult(craftingTableRecipe.assemble(input, ItemBuildContext.of(serverPlayer))); } @@ -697,10 +702,16 @@ public class RecipeEventListener implements Listener { event.setResult(null); return; } + Player player = InventoryUtils.getPlayerFromInventoryEvent(event); + ItemBuildContext itemBuildContext = ItemBuildContext.of(BukkitAdaptors.adapt(player)); + if (!smithingTrimRecipe.canUse(itemBuildContext)) { + event.setResult(null); + return; + } + SmithingInput input = getSmithingInput(inventory); if (smithingTrimRecipe.matches(input)) { - Player player = InventoryUtils.getPlayerFromInventoryEvent(event); - ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), ItemBuildContext.of(BukkitAdaptors.adapt(player))); + ItemStack result = smithingTrimRecipe.assemble(getSmithingInput(inventory), itemBuildContext); event.setResult(result); } else { event.setResult(null); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java index 430683add..b1e7d7ff1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/WorldStorageInjector.java @@ -14,7 +14,6 @@ import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.matcher.ElementMatchers; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.DelegatingBlockState; import net.momirealms.craftengine.core.block.EmptyBlock; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 8bdeb7115..18e6460d2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -152,9 +152,16 @@ public final class ImmutableBlockState extends BlockStateHolder { } @SuppressWarnings("unchecked") - public BlockEntityTicker createBlockEntityTicker(CEWorld world, BlockEntityType type) { + public BlockEntityTicker createSyncBlockEntityTicker(CEWorld world, BlockEntityType type) { EntityBlockBehavior blockBehavior = this.behavior.getEntityBehavior(); if (blockBehavior == null) return null; - return (BlockEntityTicker) blockBehavior.createBlockEntityTicker(world, this, type); + return (BlockEntityTicker) blockBehavior.createSyncBlockEntityTicker(world, this, type); + } + + @SuppressWarnings("unchecked") + public BlockEntityTicker createAsyncBlockEntityTicker(CEWorld world, BlockEntityType type) { + EntityBlockBehavior blockBehavior = this.behavior.getEntityBehavior(); + if (blockBehavior == null) return null; + return (BlockEntityTicker) blockBehavior.createAsyncBlockEntityTicker(world, this, type); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/EntityBlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/EntityBlockBehavior.java index f92b0e59a..2eb34bae7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/behavior/EntityBlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/behavior/EntityBlockBehavior.java @@ -15,7 +15,11 @@ public interface EntityBlockBehavior { BlockEntity createBlockEntity(BlockPos pos, ImmutableBlockState state); - default BlockEntityTicker createBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType blockEntityType) { + default BlockEntityTicker createSyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType blockEntityType) { + return null; + } + + default BlockEntityTicker createAsyncBlockEntityTicker(CEWorld level, ImmutableBlockState state, BlockEntityType blockEntityType) { return null; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java index 8f4632676..a95d06e39 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -9,7 +9,10 @@ import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.item.recipe.result.PostProcessor; import net.momirealms.craftengine.core.item.recipe.result.PostProcessors; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.condition.AllOfCondition; +import net.momirealms.craftengine.core.plugin.context.event.EventConditions; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -29,12 +32,21 @@ public abstract class AbstractRecipeSerializer> implement @SuppressWarnings("unchecked") protected Function[] functions(Map arguments) { - Object functions = arguments.get("functions"); + Object functions = ResourceConfigUtils.get(arguments, "functions", "function"); if (functions == null) return null; List> functionList = ResourceConfigUtils.parseConfigAsList(functions, EventFunctions::fromMap); return functionList.toArray(new Function[0]); } + protected Condition conditions(Map arguments) { + Object functions = ResourceConfigUtils.get(arguments, "conditions", "condition"); + if (functions == null) return null; + List> conditionList = ResourceConfigUtils.parseConfigAsList(functions, EventConditions::fromMap); + if (conditionList.isEmpty()) return null; + if (conditionList.size() == 1) return conditionList.getFirst(); + return new AllOfCondition<>(conditionList); + } + protected boolean showNotification(Map arguments) { return ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("show-notification", true), "show-notification"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/ConditionalRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/ConditionalRecipe.java new file mode 100644 index 000000000..fd0a8b649 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/ConditionalRecipe.java @@ -0,0 +1,8 @@ +package net.momirealms.craftengine.core.item.recipe; + +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; + +public interface ConditionalRecipe { + + boolean canUse(final PlayerOptionalContext context); +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java index d6cb7b67a..9445e2472 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java @@ -4,15 +4,17 @@ 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.result.CustomRecipeResult; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; -public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe { +public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe implements ConditionalRecipe { protected final CraftingRecipeCategory category; private final CustomRecipeResult visualResult; private final Function[] craftingFunctions; + private final Condition craftingCondition; protected CustomCraftingTableRecipe(Key id, boolean showNotification, @@ -20,11 +22,20 @@ public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe @Nullable CustomRecipeResult visualResult, String group, CraftingRecipeCategory category, - Function[] craftingFunctions) { + Function[] craftingFunctions, + Condition craftingCondition) { super(id, showNotification, result, group); this.category = category == null ? CraftingRecipeCategory.MISC : category; this.visualResult = visualResult; this.craftingFunctions = craftingFunctions; + this.craftingCondition = craftingCondition; + } + + + @Override + public boolean canUse(PlayerOptionalContext context) { + if (this.craftingCondition == null) return true; + return this.craftingCondition.test(context); } public CraftingRecipeCategory category() { 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 bad93556a..75613d5d8 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 @@ -5,8 +5,8 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; @@ -28,8 +28,9 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { String group, CraftingRecipeCategory category, Pattern pattern, - Function[] craftingFunctions) { - super(id, showNotification, result, visualResult, group, category, craftingFunctions); + Function[] craftingFunctions, + Condition craftingCondition) { + super(id, showNotification, result, visualResult, group, category, craftingFunctions, craftingCondition); this.pattern = pattern; this.parsedPattern = pattern.parse(); } @@ -174,7 +175,8 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { parseVisualResult(arguments), arguments.containsKey("group") ? arguments.get("group").toString() : null, craftingRecipeCategory(arguments), new Pattern<>(pattern.toArray(new String[0]), ingredients), - functions(arguments) + functions(arguments), + conditions(arguments) ); } @@ -188,6 +190,7 @@ public class CustomShapedRecipe extends CustomCraftingTableRecipe { VANILLA_RECIPE_HELPER.readGroup(json), VANILLA_RECIPE_HELPER.craftingCategory(json), new Pattern<>(VANILLA_RECIPE_HELPER.craftingShapedPattern(json), ingredients), + null, null ); } 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 a23c0c4bf..a60c241a4 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 @@ -4,6 +4,7 @@ import com.google.gson.JsonObject; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; +import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.util.Key; @@ -26,8 +27,9 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { String group, CraftingRecipeCategory category, List> ingredients, - Function[] craftingFunctions) { - super(id, showNotification, result, visualResult, group, category, craftingFunctions); + Function[] craftingFunctions, + Condition craftingCondition) { + super(id, showNotification, result, visualResult, group, category, craftingFunctions, craftingCondition); this.ingredients = ingredients; this.placementInfo = PlacementInfo.create(ingredients); } @@ -92,7 +94,8 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { parseVisualResult(arguments), arguments.containsKey("group") ? arguments.get("group").toString() : null, craftingRecipeCategory(arguments), ingredients, - functions(arguments) + functions(arguments), + conditions(arguments) ); } @@ -104,6 +107,7 @@ public class CustomShapelessRecipe extends CustomCraftingTableRecipe { null, VANILLA_RECIPE_HELPER.readGroup(json), VANILLA_RECIPE_HELPER.craftingCategory(json), VANILLA_RECIPE_HELPER.shapelessIngredients(json.getAsJsonArray("ingredients")).stream().map(this::toIngredient).toList(), + null, null ); } 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 9ebe583a7..852b8ff8e 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,6 +7,8 @@ import net.momirealms.craftengine.core.item.recipe.input.RecipeInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; import net.momirealms.craftengine.core.item.recipe.result.CustomRecipeResult; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.context.Condition; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Registries; @@ -20,13 +22,14 @@ import java.util.List; import java.util.Map; import java.util.Objects; -public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecipe { +public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecipe implements ConditionalRecipe { public static final Serializer SERIALIZER = new Serializer<>(); private final Ingredient base; private final Ingredient template; private final Ingredient addition; private final boolean mergeComponents; private final List processors; + private final Condition condition; public CustomSmithingTransformRecipe(Key id, boolean showNotification, @@ -35,7 +38,8 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip @Nullable Ingredient addition, CustomRecipeResult result, List processors, - boolean mergeComponents + boolean mergeComponents, + Condition condition ) { super(id, showNotification, result); this.base = base; @@ -43,6 +47,13 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip this.addition = addition; this.processors = processors; this.mergeComponents = mergeComponents; + this.condition = condition; + } + + @Override + public boolean canUse(PlayerOptionalContext context) { + if (this.condition != null) return this.condition.test(context); + return true; } @SuppressWarnings("unchecked") @@ -140,14 +151,23 @@ public class CustomSmithingTransformRecipe extends AbstractedFixedResultRecip toIngredient(addition), parseResult(arguments), ItemDataProcessors.fromMapList(processors), - mergeComponents + mergeComponents, + conditions(arguments) ); } @Override public CustomSmithingTransformRecipe readJson(Key id, JsonObject json) { - return new CustomSmithingTransformRecipe<>(id, - true, toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("template"))), Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("base")))), toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("addition"))), parseResult(VANILLA_RECIPE_HELPER.smithingResult(json.getAsJsonObject("result"))), null, true + return new CustomSmithingTransformRecipe<>( + id, + true, + toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("template"))), + Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("base")))), + toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("addition"))), + parseResult(VANILLA_RECIPE_HELPER.smithingResult(json.getAsJsonObject("result"))), + null, + true, + null ); } } 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 index 1d1195624..020a5d460 100644 --- 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 @@ -6,6 +6,8 @@ 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.context.Condition; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -18,31 +20,41 @@ import java.util.List; import java.util.Map; import java.util.Objects; -public class CustomSmithingTrimRecipe extends AbstractRecipe { +public class CustomSmithingTrimRecipe extends AbstractRecipe implements ConditionalRecipe { public static final Serializer SERIALIZER = new Serializer<>(); private final Ingredient base; private final Ingredient template; private final Ingredient addition; @Nullable // 1.21.5 private final Key pattern; + @Nullable + private final Condition condition; public CustomSmithingTrimRecipe(@NotNull Key id, boolean showNotification, @NotNull Ingredient template, @NotNull Ingredient base, @NotNull Ingredient addition, - @Nullable Key pattern + @Nullable Key pattern, + @Nullable Condition condition ) { super(id, showNotification); this.base = base; this.template = template; this.addition = addition; this.pattern = pattern; + this.condition = condition; if (pattern == null && VersionHelper.isOrAbove1_21_5()) { throw new IllegalStateException("SmithingTrimRecipe cannot have a null pattern on 1.21.5 and above."); } } + @Override + public boolean canUse(PlayerOptionalContext context) { + if (this.condition != null) return this.condition.test(context); + return true; + } + @SuppressWarnings("unchecked") @Override public T assemble(RecipeInput input, ItemBuildContext context) { @@ -122,7 +134,8 @@ public class CustomSmithingTrimRecipe extends AbstractRecipe { ResourceConfigUtils.requireNonNullOrThrow(toIngredient(template), "warning.config.recipe.smithing_trim.missing_template_type"), ResourceConfigUtils.requireNonNullOrThrow(toIngredient(base), "warning.config.recipe.smithing_trim.missing_base"), ResourceConfigUtils.requireNonNullOrThrow(toIngredient(addition), "warning.config.recipe.smithing_trim.missing_addition"), - pattern + pattern, + conditions(arguments) ); } @@ -133,7 +146,8 @@ public class CustomSmithingTrimRecipe extends AbstractRecipe { Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("template")))), Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("base")))), Objects.requireNonNull(toIngredient(VANILLA_RECIPE_HELPER.singleIngredient(json.get("addition")))), - VersionHelper.isOrAbove1_21_5() ? Key.of(json.get("pattern").getAsString()) : null + VersionHelper.isOrAbove1_21_5() ? Key.of(json.get("pattern").getAsString()) : null, + null ); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java index ac187bb3a..60098466b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java @@ -25,9 +25,12 @@ public abstract class CEWorld { protected final WorldHeight worldHeightAccessor; protected List pendingLightSections = new ArrayList<>(); protected final Set lightSections = ConcurrentHashMap.newKeySet(128); - protected final BlockEntityTickersList tickingBlockEntities = new BlockEntityTickersList(); - protected final List pendingTickingBlockEntities = new ArrayList<>(); - protected volatile boolean isTickingBlockEntities = false; + protected final BlockEntityTickersList tickingSyncBlockEntities = new BlockEntityTickersList(); + protected final List pendingSyncTickingBlockEntities = new ArrayList<>(); + protected final BlockEntityTickersList tickingAsyncBlockEntities = new BlockEntityTickersList(); + protected final List pendingAsyncTickingBlockEntities = new ArrayList<>(); + protected volatile boolean isTickingSyncBlockEntities = false; + protected volatile boolean isTickingAsyncBlockEntities = false; protected volatile boolean isUpdatingLights = false; protected SchedulerTask syncTickTask; protected SchedulerTask asyncTickTask; @@ -176,13 +179,14 @@ public abstract class CEWorld { } public void syncTick() { - this.tickBlockEntities(); + this.tickSyncBlockEntities(); if (!Config.asyncLightUpdate()) { this.updateLight(); } } public void asyncTick() { + this.tickAsyncBlockEntities(); if (Config.asyncLightUpdate()) { this.updateLight(); } @@ -190,32 +194,61 @@ public abstract class CEWorld { public abstract void updateLight(); - public void addBlockEntityTicker(TickingBlockEntity ticker) { - if (this.isTickingBlockEntities) { - this.pendingTickingBlockEntities.add(ticker); + public void addSyncBlockEntityTicker(TickingBlockEntity ticker) { + if (this.isTickingSyncBlockEntities) { + this.pendingSyncTickingBlockEntities.add(ticker); } else { - this.tickingBlockEntities.add(ticker); + this.tickingSyncBlockEntities.add(ticker); } } - protected void tickBlockEntities() { - this.isTickingBlockEntities = true; - if (!this.pendingTickingBlockEntities.isEmpty()) { - this.tickingBlockEntities.addAll(this.pendingTickingBlockEntities); - this.pendingTickingBlockEntities.clear(); + public void addAsyncBlockEntityTicker(TickingBlockEntity ticker) { + if (this.isTickingAsyncBlockEntities) { + this.pendingAsyncTickingBlockEntities.add(ticker); + } else { + this.tickingAsyncBlockEntities.add(ticker); } - if (!this.tickingBlockEntities.isEmpty()) { - Object[] entities = this.tickingBlockEntities.elements(); - for (int i = 0, size = this.tickingBlockEntities.size(); i < size; i++) { + } + + protected void tickSyncBlockEntities() { + this.isTickingSyncBlockEntities = true; + if (!this.pendingSyncTickingBlockEntities.isEmpty()) { + this.tickingSyncBlockEntities.addAll(this.pendingSyncTickingBlockEntities); + this.pendingSyncTickingBlockEntities.clear(); + } + if (!this.tickingSyncBlockEntities.isEmpty()) { + Object[] entities = this.tickingSyncBlockEntities.elements(); + for (int i = 0, size = this.tickingSyncBlockEntities.size(); i < size; i++) { TickingBlockEntity entity = (TickingBlockEntity) entities[i]; if (entity.isValid()) { entity.tick(); } else { - this.tickingBlockEntities.markAsRemoved(i); + this.tickingSyncBlockEntities.markAsRemoved(i); } } - this.tickingBlockEntities.removeMarkedEntries(); + this.tickingSyncBlockEntities.removeMarkedEntries(); } - this.isTickingBlockEntities = false; + this.isTickingSyncBlockEntities = false; + } + + protected void tickAsyncBlockEntities() { + this.isTickingAsyncBlockEntities = true; + if (!this.pendingAsyncTickingBlockEntities.isEmpty()) { + this.tickingAsyncBlockEntities.addAll(this.pendingAsyncTickingBlockEntities); + this.pendingAsyncTickingBlockEntities.clear(); + } + if (!this.tickingAsyncBlockEntities.isEmpty()) { + Object[] entities = this.tickingAsyncBlockEntities.elements(); + for (int i = 0, size = this.tickingAsyncBlockEntities.size(); i < size; i++) { + TickingBlockEntity entity = (TickingBlockEntity) entities[i]; + if (entity.isValid()) { + entity.tick(); + } else { + this.tickingAsyncBlockEntities.markAsRemoved(i); + } + } + this.tickingAsyncBlockEntities.removeMarkedEntries(); + } + this.isTickingAsyncBlockEntities = false; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java index 442ac8999..d48e09472 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/CEChunk.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.world.chunk; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.momirealms.craftengine.core.block.EmptyBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; import net.momirealms.craftengine.core.block.entity.BlockEntity; import net.momirealms.craftengine.core.block.entity.render.ConstantBlockEntityRenderer; import net.momirealms.craftengine.core.block.entity.render.DynamicBlockEntityRenderer; @@ -27,7 +28,8 @@ public class CEChunk { public final CESection[] sections; public final WorldHeight worldHeightAccessor; public final Map blockEntities; // 从区域线程上访问,安全 - public final Map tickingBlockEntitiesByPos; // 从区域线程上访问,安全 + public final Map tickingSyncBlockEntitiesByPos; // 从区域线程上访问,安全 + public final Map tickingAsyncBlockEntitiesByPos; // 从区域线程上访问,安全 public final Map constantBlockEntityRenderers; // 会从区域线程上读写,netty线程上读取 public final Map dynamicBlockEntityRenderers; // 会从区域线程上读写,netty线程上读取 private final ReentrantReadWriteLock renderLock = new ReentrantReadWriteLock(); @@ -42,7 +44,8 @@ public class CEChunk { this.blockEntities = new Object2ObjectOpenHashMap<>(10, 0.5f); this.constantBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f); this.dynamicBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f); - this.tickingBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f); + this.tickingSyncBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f); + this.tickingAsyncBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f); this.fillEmptySection(); } @@ -51,7 +54,8 @@ public class CEChunk { this.chunkPos = chunkPos; this.worldHeightAccessor = world.worldHeight(); this.dynamicBlockEntityRenderers = new Object2ObjectOpenHashMap<>(10, 0.5f); - this.tickingBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f); + this.tickingSyncBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f); + this.tickingAsyncBlockEntitiesByPos = new Object2ObjectOpenHashMap<>(10, 0.5f); int sectionCount = this.worldHeightAccessor.getSectionsCount(); this.sections = new CESection[sectionCount]; if (sections != null) { @@ -198,27 +202,51 @@ public class CEChunk { this.blockEntities.values().forEach(e -> e.setValid(false)); this.constantBlockEntityRenderers.values().forEach(ConstantBlockEntityRenderer::deactivate); this.dynamicBlockEntityRenderers.clear(); - this.tickingBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE)); - this.tickingBlockEntitiesByPos.clear(); + this.tickingSyncBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE)); + this.tickingSyncBlockEntitiesByPos.clear(); + this.tickingAsyncBlockEntitiesByPos.values().forEach((ticker) -> ticker.setTicker(DummyTickingBlockEntity.INSTANCE)); + this.tickingAsyncBlockEntitiesByPos.clear(); } + @SuppressWarnings("unchecked") public void replaceOrCreateTickingBlockEntity(T blockEntity) { ImmutableBlockState blockState = blockEntity.blockState(); - BlockEntityTicker ticker = blockState.createBlockEntityTicker(this.world, blockEntity.type()); - if (ticker != null) { - this.tickingBlockEntitiesByPos.compute(blockEntity.pos(), ((pos, previousTicker) -> { - TickingBlockEntity newTicker = new TickingBlockEntityImpl<>(this, blockEntity, ticker); - if (previousTicker != null) { - previousTicker.setTicker(newTicker); - return previousTicker; - } else { - ReplaceableTickingBlockEntity replaceableTicker = new ReplaceableTickingBlockEntity(newTicker); - this.world.addBlockEntityTicker(replaceableTicker); - return replaceableTicker; - } - })); - } else { + EntityBlockBehavior blockBehavior = blockState.behavior().getEntityBehavior(); + if (blockBehavior == null) { this.removeBlockEntityTicker(blockEntity.pos()); + } else { + BlockEntityTicker syncTicker = (BlockEntityTicker) blockBehavior.createSyncBlockEntityTicker(this.world, blockState, blockEntity.type()); + if (syncTicker != null) { + this.tickingSyncBlockEntitiesByPos.compute(blockEntity.pos(), ((pos, previousTicker) -> { + TickingBlockEntity newTicker = new TickingBlockEntityImpl<>(this, blockEntity, syncTicker); + if (previousTicker != null) { + previousTicker.setTicker(newTicker); + return previousTicker; + } else { + ReplaceableTickingBlockEntity replaceableTicker = new ReplaceableTickingBlockEntity(newTicker); + this.world.addSyncBlockEntityTicker(replaceableTicker); + return replaceableTicker; + } + })); + } else { + this.removeSyncBlockEntityTicker(blockEntity.pos()); + } + BlockEntityTicker asyncTicker = (BlockEntityTicker) blockBehavior.createAsyncBlockEntityTicker(this.world, blockState, blockEntity.type()); + if (asyncTicker != null) { + this.tickingAsyncBlockEntitiesByPos.compute(blockEntity.pos(), ((pos, previousTicker) -> { + TickingBlockEntity newTicker = new TickingBlockEntityImpl<>(this, blockEntity, asyncTicker); + if (previousTicker != null) { + previousTicker.setTicker(newTicker); + return previousTicker; + } else { + ReplaceableTickingBlockEntity replaceableTicker = new ReplaceableTickingBlockEntity(newTicker); + this.world.addAsyncBlockEntityTicker(replaceableTicker); + return replaceableTicker; + } + })); + } else { + this.removeAsyncBlockEntityTicker(blockEntity.pos()); + } } } @@ -250,13 +278,25 @@ public class CEChunk { } } - private void removeBlockEntityTicker(BlockPos pos) { - ReplaceableTickingBlockEntity blockEntity = this.tickingBlockEntitiesByPos.remove(pos); - if (blockEntity != null) { - blockEntity.setTicker(DummyTickingBlockEntity.INSTANCE); + private void removeSyncBlockEntityTicker(BlockPos pos) { + ReplaceableTickingBlockEntity e1 = this.tickingSyncBlockEntitiesByPos.remove(pos); + if (e1 != null) { + e1.setTicker(DummyTickingBlockEntity.INSTANCE); } } + private void removeAsyncBlockEntityTicker(BlockPos pos) { + ReplaceableTickingBlockEntity e2 = this.tickingAsyncBlockEntitiesByPos.remove(pos); + if (e2 != null) { + e2.setTicker(DummyTickingBlockEntity.INSTANCE); + } + } + + private void removeBlockEntityTicker(BlockPos pos) { + removeSyncBlockEntityTicker(pos); + removeAsyncBlockEntityTicker(pos); + } + public void setBlockEntity(BlockEntity blockEntity) { BlockPos pos = blockEntity.pos(); ImmutableBlockState blockState = this.getBlockState(pos); diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java index 9967eb586..81948b867 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/packet/MCSection.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.world.chunk.packet; import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.IndexedIterable; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; -import net.momirealms.craftengine.core.world.chunk.ReadableContainer; public class MCSection { private short nonEmptyBlockCount; diff --git a/gradle.properties b/gradle.properties index 873f9bbbc..3dfd4ae54 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.1 +project_version=0.0.63.2 config_version=45 lang_version=29 project_group=net.momirealms From b8fb2d1201f3f370c9a357ea161e334c95617a53 Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Wed, 17 Sep 2025 20:24:58 +0800 Subject: [PATCH 012/125] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B2=99=E5=8F=91?= =?UTF-8?q?=E7=9A=84=E6=94=AF=E6=8C=81=E5=BD=A2=E7=8A=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/default/configuration/blocks/sofa.yml | 1 + .../core/item/recipe/AbstractRecipeSerializer.java | 6 +++--- .../core/item/recipe/CustomCraftingTableRecipe.java | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml b/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml index 1f4a86917..131392513 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml @@ -23,6 +23,7 @@ items: is-redstone-conductor: false push-reaction: block instrument: bass + support-shape: cobweb sounds: break: minecraft:block.wood.break fall: minecraft:block.wood.fall diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java index a95d06e39..43dd6dfc5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/AbstractRecipeSerializer.java @@ -39,9 +39,9 @@ public abstract class AbstractRecipeSerializer> implement } protected Condition conditions(Map arguments) { - Object functions = ResourceConfigUtils.get(arguments, "conditions", "condition"); - if (functions == null) return null; - List> conditionList = ResourceConfigUtils.parseConfigAsList(functions, EventConditions::fromMap); + Object conditions = ResourceConfigUtils.get(arguments, "conditions", "condition"); + if (conditions == null) return null; + List> conditionList = ResourceConfigUtils.parseConfigAsList(conditions, EventConditions::fromMap); if (conditionList.isEmpty()) return null; if (conditionList.size() == 1) return conditionList.getFirst(); return new AllOfCondition<>(conditionList); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java index 9445e2472..13783dabc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/recipe/CustomCraftingTableRecipe.java @@ -31,7 +31,6 @@ public abstract class CustomCraftingTableRecipe extends AbstractGroupedRecipe this.craftingCondition = craftingCondition; } - @Override public boolean canUse(PlayerOptionalContext context) { if (this.craftingCondition == null) return true; From 7c8005c6f5973f8c57db7d47ad56a9ef278f3871 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Thu, 18 Sep 2025 01:01:58 +0800 Subject: [PATCH 013/125] =?UTF-8?q?feat(block):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=A0=85=E6=A0=8F=E6=96=B9=E5=9D=97=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/BukkitBlockBehaviors.java | 2 + .../block/behavior/FenceBlockBehavior.java | 155 ++++++++++++++++++ .../behavior/FenceGateBlockBehavior.java | 21 ++- .../reflection/minecraft/CoreReflections.java | 7 + .../plugin/reflection/minecraft/MBlocks.java | 10 ++ .../plugin/reflection/minecraft/MTagKeys.java | 3 + .../bukkit/util/BlockStateUtils.java | 8 +- .../craftengine/bukkit/util/BlockUtils.java | 22 +++ .../src/main/resources/translations/en.yml | 4 + .../src/main/resources/translations/zh_cn.yml | 4 + .../craftengine/core/world/BlockPos.java | 44 +++++ .../craftengine/core/world/Vec3i.java | 33 ++++ gradle.properties | 6 +- 13 files changed, 310 insertions(+), 9 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockUtils.java 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 f6cc1c58e..4070b0f48 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 @@ -36,6 +36,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key LIQUID_FLOWABLE_BLOCK = Key.from("craftengine:liquid_flowable_block"); public static final Key SIMPLE_PARTICLE_BLOCK = Key.from("craftengine:simple_particle_block"); public static final Key WALL_TORCH_PARTICLE_BLOCK = Key.from("craftengine:wall_torch_particle_block"); + public static final Key FENCE_BLOCK = Key.from("craftengine:fence_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -70,5 +71,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(LIQUID_FLOWABLE_BLOCK, LiquidFlowableBlockBehavior.FACTORY); register(SIMPLE_PARTICLE_BLOCK, SimpleParticleBlockBehavior.FACTORY); register(WALL_TORCH_PARTICLE_BLOCK, WallTorchParticleBlockBehavior.FACTORY); + register(FENCE_BLOCK, FenceBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java new file mode 100644 index 000000000..d167464d2 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java @@ -0,0 +1,155 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MTagKeys; +import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.BooleanProperty; +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.context.BlockPlaceContext; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.registry.Holder; +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.HorizontalDirection; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.World; + +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Callable; + +public class FenceBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final BooleanProperty northProperty; + private final BooleanProperty eastProperty; + private final BooleanProperty southProperty; + private final BooleanProperty westProperty; + private final Object selfBlockTag; + private final Object connectableBlockTag; + private final boolean canLeash; + + public FenceBlockBehavior(CustomBlock customBlock, + BooleanProperty northProperty, + BooleanProperty eastProperty, + BooleanProperty southProperty, + BooleanProperty westProperty, + Object selfBlockTag, + Object connectableBlockTag, + boolean canLeash) { + super(customBlock); + this.northProperty = northProperty; + this.eastProperty = eastProperty; + this.southProperty = southProperty; + this.westProperty = westProperty; + this.selfBlockTag = selfBlockTag; + this.connectableBlockTag = connectableBlockTag; + this.canLeash = canLeash; + } + + @Override + public boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) { + return false; + } + + public boolean connectsTo(BlockStateWrapper state, boolean isSideSolid, HorizontalDirection direction) { + boolean isSameFence = this.isSameFence(state); + boolean flag = CoreReflections.clazz$FenceGateBlock.isInstance(BlockStateUtils.getBlockOwner(state.literalObject())) + ? FastNMS.INSTANCE.method$FenceGateBlock$connectsToDirection(state.literalObject(), DirectionUtils.toNMSDirection(direction.toDirection())) + : FenceGateBlockBehavior.connectsToDirection(state, direction); + return !BlockUtils.isExceptionForConnection(state) && isSideSolid || isSameFence || flag; + } + + private boolean isSameFence(BlockStateWrapper state) { + Object blockState = state.literalObject(); + return FastNMS.INSTANCE.method$BlockStateBase$is(blockState, this.selfBlockTag) + && FastNMS.INSTANCE.method$BlockStateBase$is(blockState, this.connectableBlockTag) + == FastNMS.INSTANCE.method$BlockStateBase$is(this.customBlock.defaultState().customBlockState().literalObject(), this.connectableBlockTag); + } + + @Override + public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) { + if (!this.canLeash) return InteractionResult.PASS; + Player player = context.getPlayer(); + if (player == null) return InteractionResult.PASS; + if (FastNMS.INSTANCE.method$LeadItem$bindPlayerMobs(player.serverPlayer(), context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()))) { + player.swingHand(InteractionHand.MAIN_HAND); + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } + + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + World level = context.getLevel(); + BlockPos clickedPos = context.getClickedPos(); + Object fluidState = FastNMS.INSTANCE.method$BlockGetter$getFluidState(level.serverWorld(), LocationUtils.toBlockPos(clickedPos)); + BlockPos blockPos = clickedPos.north(); + BlockPos blockPos1 = clickedPos.east(); + BlockPos blockPos2 = clickedPos.south(); + BlockPos blockPos3 = clickedPos.west(); + BlockStateWrapper blockState = level.getBlockAt(blockPos).blockState(); + BlockStateWrapper blockState1 = level.getBlockAt(blockPos1).blockState(); + BlockStateWrapper blockState2 = level.getBlockAt(blockPos2).blockState(); + BlockStateWrapper blockState3 = level.getBlockAt(blockPos3).blockState(); + BooleanProperty waterlogged = (BooleanProperty) state.owner().value().getProperty("waterlogged"); + if (waterlogged != null) { + state = state.with(waterlogged, FastNMS.INSTANCE.method$FluidState$getType(fluidState) == MFluids.WATER); + } + return state + .with(this.northProperty, this.connectsTo(blockState, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(blockState.literalObject(), level.serverWorld(), LocationUtils.toBlockPos(blockPos), CoreReflections.instance$Direction$SOUTH, CoreReflections.instance$SupportType$FULL), HorizontalDirection.SOUTH)) + .with(this.eastProperty, this.connectsTo(blockState1, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(blockState1.literalObject(), level.serverWorld(), LocationUtils.toBlockPos(blockPos1), CoreReflections.instance$Direction$WEST, CoreReflections.instance$SupportType$FULL), HorizontalDirection.WEST)) + .with(this.southProperty, this.connectsTo(blockState2, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(blockState2.literalObject(), level.serverWorld(), LocationUtils.toBlockPos(blockPos2), CoreReflections.instance$Direction$NORTH, CoreReflections.instance$SupportType$FULL), HorizontalDirection.NORTH)) + .with(this.westProperty, this.connectsTo(blockState3, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(blockState3.literalObject(), level.serverWorld(), LocationUtils.toBlockPos(blockPos3), CoreReflections.instance$Direction$EAST, CoreReflections.instance$SupportType$FULL), HorizontalDirection.EAST)); + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Optional optionalState = BlockStateUtils.getOptionalCustomBlockState(args[0]); + BooleanProperty waterlogged = (BooleanProperty) optionalState + .map(BlockStateHolder::owner) + .map(Holder::value) + .map(block -> block.getProperty("waterlogged")) + .orElse(null); + if (waterlogged != null) { + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleFluidTick(args[updateShape$level], args[updateShape$blockPos], MFluids.WATER, 5); + } + if (DirectionUtils.fromNMSDirection(args[updateShape$direction]).axis().isHorizontal() && optionalState.isPresent()) { + Direction direction = DirectionUtils.fromNMSDirection(args[updateShape$direction]); + ImmutableBlockState state = optionalState.get(); + if (state.owner() != null) { + BooleanProperty booleanProperty = (BooleanProperty) state.owner().value().getProperty(direction.name().toLowerCase(Locale.ROOT)); + if (booleanProperty != null) { + BlockStateWrapper wrapper = BlockStateUtils.toBlockStateWrapper(args[updateShape$neighborState]); + return state.with(booleanProperty, this.connectsTo(wrapper, FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(wrapper.literalObject(), args[updateShape$level], args[5], DirectionUtils.toNMSDirection(direction.opposite()), CoreReflections.instance$SupportType$FULL), direction.opposite().toHorizontalDirection())).customBlockState().literalObject(); + } + } + } + return superMethod.call(); + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + BooleanProperty north = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("north"), "warning.config.block.behavior.fence.missing_north"); + BooleanProperty east = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("east"), "warning.config.block.behavior.fence.missing_east"); + BooleanProperty south = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("south"), "warning.config.block.behavior.fence.missing_south"); + BooleanProperty west = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("west"), "warning.config.block.behavior.fence.missing_west"); + Object selfBlockTag = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("self-block-tag", "minecraft:fences").toString()))); + selfBlockTag = selfBlockTag != null ? selfBlockTag : MTagKeys.Block$FENCES; + Object connectableBlockTag = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("connectable-block-tag", "minecraft:wooden_fences").toString()))); + connectableBlockTag = connectableBlockTag != null ? connectableBlockTag : MTagKeys.Block$WOODEN_FENCES; + boolean canLeash = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-leash", false), "can-leash"); + return new FenceBlockBehavior(block, north, east, south, west, selfBlockTag, connectableBlockTag, canLeash); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceGateBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceGateBlockBehavior.java index 99f897792..03f0d1a11 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceGateBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceGateBlockBehavior.java @@ -10,10 +10,7 @@ import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.InteractUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; -import net.momirealms.craftengine.core.block.BlockBehavior; -import net.momirealms.craftengine.core.block.CustomBlock; -import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.block.UpdateOption; +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.entity.player.InteractionResult; @@ -262,6 +259,22 @@ public class FenceGateBlockBehavior extends BukkitBlockBehavior { } } + public static boolean connectsToDirection(BlockStateWrapper state, HorizontalDirection direction) { + FenceGateBlockBehavior fence = BlockStateUtils.getOptionalCustomBlockState(state.literalObject()) + .map(ImmutableBlockState::behavior) + .flatMap(behavior -> behavior.getAs(FenceGateBlockBehavior.class)) + .orElse(null); + if (fence == null) return false; + Direction facing = null; + ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(state.literalObject()).orElse(null); + if (customState == null) return false; + Property facingProperty = customState.owner().value().getProperty("facing"); + if (facingProperty != null && facingProperty.valueClass() == HorizontalDirection.class) { + facing = ((HorizontalDirection) customState.get(facingProperty)).toDirection(); + } + return facing != null && facing.axis() == direction.toDirection().clockWise().axis(); + } + public static class Factory implements BlockBehaviorFactory { @Override 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 48eb0072e..d704b2335 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 @@ -4389,4 +4389,11 @@ public final class CoreReflections { public static final Constructor constructor$AdvancementHolder = Optional.ofNullable(clazz$AdvancementHolder) .map(it -> ReflectionUtils.getConstructor(it, clazz$ResourceLocation, clazz$Advancement)) .orElse(null); + + public static final Class clazz$FenceGateBlock = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.level.block.BlockFenceGate", + "world.level.block.FenceGateBlock" + ) + ); } 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 d8971adba..d9c489fba 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 @@ -22,6 +22,11 @@ public final class MBlocks { public static final Object WATER$defaultState; public static final Object TNT; public static final Object TNT$defaultState; + public static final Object BARRIER; + public static final Object CARVED_PUMPKIN; + public static final Object JACK_O_LANTERN; + public static final Object MELON; + public static final Object PUMPKIN; private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); @@ -45,5 +50,10 @@ public final class MBlocks { WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); TNT = getById("tnt"); TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT); + BARRIER = getById("barrier"); + CARVED_PUMPKIN = getById("carved_pumpkin"); + JACK_O_LANTERN = getById("jack_o_lantern"); + MELON = getById("melon"); + PUMPKIN = getById("pumpkin"); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java index bc3a11172..fe3440027 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java @@ -9,6 +9,9 @@ public final class MTagKeys { public static final Object Item$WOOL = create(MRegistries.ITEM, "wool"); public static final Object Block$WALLS = create(MRegistries.BLOCK, "walls"); + public static final Object Block$SHULKER_BOXES = create(MRegistries.BLOCK, "shulker_boxes"); + public static final Object Block$FENCES = create(MRegistries.BLOCK, "fences"); + public static final Object Block$WOODEN_FENCES = create(MRegistries.BLOCK, "wooden_fences"); private static Object create(Object registry, String location) { Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location); 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 3d3a592f7..a75f5808e 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 @@ -45,8 +45,12 @@ public final class BlockStateUtils { public static BlockStateWrapper toBlockStateWrapper(BlockData blockData) { Object state = blockDataToBlockState(blockData); - int id = blockStateToId(state); - return new BukkitBlockStateWrapper(state, id); + return toBlockStateWrapper(state); + } + + public static BlockStateWrapper toBlockStateWrapper(Object blockState) { + int id = blockStateToId(blockState); + return new BukkitBlockStateWrapper(blockState, id); } public static boolean isCorrectTool(@NotNull ImmutableBlockState state, @Nullable Item itemInHand) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockUtils.java new file mode 100644 index 000000000..08546729e --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/BlockUtils.java @@ -0,0 +1,22 @@ +package net.momirealms.craftengine.bukkit.util; + +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.plugin.reflection.minecraft.MTagKeys; +import net.momirealms.craftengine.core.block.BlockStateWrapper; + +public final class BlockUtils { + private BlockUtils() {} + + public static boolean isExceptionForConnection(BlockStateWrapper state) { + Object blockState = state.literalObject(); + return CoreReflections.clazz$LeavesBlock.isInstance(BlockStateUtils.getBlockOwner(blockState)) + || FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.BARRIER) + || FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.CARVED_PUMPKIN) + || FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.JACK_O_LANTERN) + || FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.MELON) + || FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, MBlocks.PUMPKIN) + || FastNMS.INSTANCE.method$BlockStateBase$is(blockState, MTagKeys.Block$SHULKER_BOXES); + } +} diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 4fa46057b..559efd97f 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -321,6 +321,10 @@ warning.config.block.behavior.double_high.missing_half: "Issue found in warning.config.block.behavior.change_over_time.missing_next_block: "Issue found in file - The block '' is missing the required 'next_block' argument for 'change_over_time_block' behavior." warning.config.block.behavior.surface_attached.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'surface_attached_block' behavior." warning.config.block.behavior.wall_torch_particle.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'wall_torch_particle_block' behavior." +warning.config.block.behavior.fence.missing_north: "Issue found in file - The block '' is missing the required 'north' property for 'fence_block' behavior." +warning.config.block.behavior.fence.missing_east: "Issue found in file - The block '' is missing the required 'east' property for 'fence_block' behavior." +warning.config.block.behavior.fence.missing_south: "Issue found in file - The block '' is missing the required 'south' property for 'fence_block' behavior." +warning.config.block.behavior.fence.missing_west: "Issue found in file - The block '' is missing the required 'west' property for 'fence_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.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." 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: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 8a5413621..d15fae40a 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -315,6 +315,10 @@ warning.config.block.behavior.double_high.missing_half: "在文件 在文件 发现问题 - 方块 '' 的 'change_over_time_block' 行为缺少必需的 'next-block' 参数" warning.config.block.behavior.surface_attached.missing_facing: "在文件 发现问题 - 方块 '' 的 'surface_attached_block' 行为缺少必需的 'facing' 属性" warning.config.block.behavior.wall_torch_particle.missing_facing: "在文件 发现问题 - 配置项 '' 的 'wall_torch_particle_block' 行为缺少必需的 'facing' 属性" +warning.config.block.behavior.fence.missing_north: "在文件 发现问题 - 方块 '' 的 'fence_block' 行为缺少必需的 'north' 属性" +warning.config.block.behavior.fence.missing_east: "在文件 发现问题 - 方块 '' 的 'fence_block' 行为缺少必需的 'east' 属性" +warning.config.block.behavior.fence.missing_south: "在文件 发现问题 - 方块 '' 的 'fence_block' 行为缺少必需的 'south' 属性" +warning.config.block.behavior.fence.missing_west: "在文件 发现问题 - 方块 '' 的 'fence_block' 行为缺少必需的 'west' 属性" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java b/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java index 0bc751b85..88fe4b680 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java @@ -55,4 +55,48 @@ public class BlockPos extends Vec3i { public BlockPos offset(int x, int y, int z) { return x == 0 && y == 0 && z == 0 ? this : new BlockPos(this.x() + x, this.y() + y, this.z() + z); } + + public BlockPos immutable() { + return this; + } + + @Override + public BlockPos north() { + return new BlockPos(this.x(), this.y(), this.z() - 1); + } + + @Override + public BlockPos north(int distance) { + return distance == 0 ? this.immutable() : new BlockPos(this.x(), this.y(), this.z() - distance); + } + + @Override + public BlockPos south() { + return new BlockPos(this.x(), this.y(), this.z() + 1); + } + + @Override + public BlockPos south(int distance) { + return distance == 0 ? this.immutable() : new BlockPos(this.x(), this.y(), this.z() + distance); + } + + @Override + public BlockPos west() { + return new BlockPos(this.x() - 1, this.y(), this.z()); + } + + @Override + public BlockPos west(int distance) { + return distance == 0 ? this.immutable() : new BlockPos(this.x() - distance, this.y(), this.z()); + } + + @Override + public BlockPos east() { + return new BlockPos(this.x() + 1, this.y(), this.z()); + } + + @Override + public BlockPos east(int distance) { + return distance == 0 ? this.immutable() : new BlockPos(this.x() + distance, this.y(), this.z()); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/Vec3i.java b/core/src/main/java/net/momirealms/craftengine/core/world/Vec3i.java index 9413aff03..82b2e4bbb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/Vec3i.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/Vec3i.java @@ -92,4 +92,37 @@ public class Vec3i implements Comparable { return this.y() - vec3i.y(); } } + + public Vec3i north() { + return this.north(1); + } + + public Vec3i north(int distance) { + return this.relative(Direction.NORTH, distance); + } + + public Vec3i south() { + return this.south(1); + } + + public Vec3i south(int distance) { + return this.relative(Direction.SOUTH, distance); + } + + public Vec3i west() { + return this.west(1); + } + + public Vec3i west(int distance) { + return this.relative(Direction.WEST, distance); + } + + public Vec3i east() { + return this.east(1); + } + + public Vec3i east(int distance) { + return this.relative(Direction.EAST, distance); + } + } diff --git a/gradle.properties b/gradle.properties index 3dfd4ae54..e3cd09f69 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,8 +3,8 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.63.2 -config_version=45 -lang_version=29 +config_version=46 +lang_version=30 project_group=net.momirealms latest_supported_version=1.21.8 @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.90 +nms_helper_version=1.0.91 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1 From 5347d1e9f1451108cb3eb6b34ccf6baa342ac310 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Thu, 18 Sep 2025 02:52:57 +0800 Subject: [PATCH 014/125] =?UTF-8?q?feat(block):=20=E6=94=B9=E8=BF=9BDirect?= =?UTF-8?q?ionalAttachedBlockBehavior?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DirectionalAttachedBlockBehavior.java | 98 ++++++++++++++++--- 1 file changed, 85 insertions(+), 13 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java index 228bab889..5e8383ef5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java @@ -4,6 +4,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.MBlocks; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.BlockTags; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.core.block.BlockBehavior; @@ -13,24 +14,41 @@ import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.util.Direction; -import net.momirealms.craftengine.core.util.HorizontalDirection; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.World; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; -import java.util.Map; +import java.util.*; import java.util.concurrent.Callable; -public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior { +public class DirectionalAttachedBlockBehavior extends AbstractCanSurviveBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property facingProperty; private final boolean isSixDirection; + private final List tagsCanSurviveOn; + private final Set blockStatesCanSurviveOn; + private final Set customBlocksCansSurviveOn; + private final boolean blacklistMode; - public DirectionalAttachedBlockBehavior(CustomBlock customBlock, Property facingProperty, boolean isSixDirection) { - super(customBlock); + public DirectionalAttachedBlockBehavior(CustomBlock customBlock, + Property facingProperty, + boolean isSixDirection, + int delay, + boolean blacklist, + List tagsCanSurviveOn, + Set blockStatesCanSurviveOn, + Set customBlocksCansSurviveOn) { + super(customBlock, delay); this.facingProperty = facingProperty; this.isSixDirection = isSixDirection; + this.tagsCanSurviveOn = tagsCanSurviveOn; + this.blockStatesCanSurviveOn = blockStatesCanSurviveOn; + this.customBlocksCansSurviveOn = customBlocksCansSurviveOn; + this.blacklistMode = blacklist; } @Override @@ -51,8 +69,8 @@ public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior { } @Override - public boolean canSurvive(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + protected boolean canSurvive(Object thisBlock, Object blockState, Object world, Object pos) throws Exception { + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(blockState).orElse(null); if (state == null) return false; DirectionalAttachedBlockBehavior behavior = state.behavior().getAs(DirectionalAttachedBlockBehavior.class).orElse(null); if (behavior == null) return false; @@ -62,10 +80,34 @@ public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior { } else { direction = ((HorizontalDirection) state.get(behavior.facingProperty)).opposite().toDirection(); } - BlockPos blockPos = LocationUtils.fromBlockPos(args[2]).relative(direction); + BlockPos blockPos = LocationUtils.fromBlockPos(pos).relative(direction); Object nmsPos = LocationUtils.toBlockPos(blockPos); - Object nmsState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(args[1], nmsPos); - return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(nmsState, args[1], nmsPos, DirectionUtils.toNMSDirection(direction), CoreReflections.instance$SupportType$FULL); + Object nmsState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, nmsPos); + return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(nmsState, world, nmsPos, DirectionUtils.toNMSDirection(direction), CoreReflections.instance$SupportType$FULL) + && mayPlaceOn(nmsState); + } + + private boolean mayPlaceOn(Object state) { + for (Object tag : this.tagsCanSurviveOn) { + if (FastNMS.INSTANCE.method$BlockStateBase$is(state, tag)) { + return !this.blacklistMode; + } + } + Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state); + if (optionalCustomState.isEmpty()) { + if (!this.blockStatesCanSurviveOn.isEmpty() && this.blockStatesCanSurviveOn.contains(state)) { + return !this.blacklistMode; + } + } else { + ImmutableBlockState belowCustomState = optionalCustomState.get(); + if (this.customBlocksCansSurviveOn.contains(belowCustomState.owner().value().id().toString())) { + return !this.blacklistMode; + } + if (this.customBlocksCansSurviveOn.contains(belowCustomState.toString())) { + return !this.blacklistMode; + } + } + return this.blacklistMode; } @SuppressWarnings("unchecked") @@ -101,7 +143,37 @@ public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior { if (!(isHorizontalDirection || isDirection)) { throw new LocalizedResourceConfigException("warning.config.block.behavior.surface_attached.missing_facing"); } - return new DirectionalAttachedBlockBehavior(block, facing, isDirection); + Tuple, Set, Set> tuple = readTagsAndState(arguments); + int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); + boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", true), "blacklist"); + return new DirectionalAttachedBlockBehavior(block, facing, isDirection, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right()); } } + + @SuppressWarnings("DuplicatedCode") + private static Tuple, Set, Set> readTagsAndState(Map arguments) { + List mcTags = new ArrayList<>(); + for (String tag : MiscUtils.getAsStringList(arguments.getOrDefault("wall-block-tags", List.of()))) { + mcTags.add(BlockTags.getOrCreate(Key.of(tag))); + } + Set mcBlocks = new HashSet<>(); + Set customBlocks = new HashSet<>(); + for (String blockStateStr : MiscUtils.getAsStringList(arguments.getOrDefault("wall-blocks", List.of()))) { + int index = blockStateStr.indexOf('['); + Key blockType = index != -1 ? Key.from(blockStateStr.substring(0, index)) : Key.from(blockStateStr); + Material material = Registry.MATERIAL.get(new NamespacedKey(blockType.namespace(), blockType.value())); + if (material != null) { + if (index == -1) { + // vanilla + mcBlocks.addAll(BlockStateUtils.getAllVanillaBlockStates(blockType)); + } else { + mcBlocks.add(BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(blockStateStr))); + } + } else { + // custom maybe + customBlocks.add(blockStateStr); + } + } + return new Tuple<>(mcTags, mcBlocks, customBlocks); + } } From 9c2bedff00e9b45048c86b31f4118c0013f0572e Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Thu, 18 Sep 2025 02:56:16 +0800 Subject: [PATCH 015/125] =?UTF-8?q?=E6=94=B9=E5=90=8D=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/DirectionalAttachedBlockBehavior.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java index 5e8383ef5..1b33c2747 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java @@ -153,12 +153,12 @@ public class DirectionalAttachedBlockBehavior extends AbstractCanSurviveBlockBeh @SuppressWarnings("DuplicatedCode") private static Tuple, Set, Set> readTagsAndState(Map arguments) { List mcTags = new ArrayList<>(); - for (String tag : MiscUtils.getAsStringList(arguments.getOrDefault("wall-block-tags", List.of()))) { + for (String tag : MiscUtils.getAsStringList(arguments.getOrDefault("attached-block-tags", List.of()))) { mcTags.add(BlockTags.getOrCreate(Key.of(tag))); } Set mcBlocks = new HashSet<>(); Set customBlocks = new HashSet<>(); - for (String blockStateStr : MiscUtils.getAsStringList(arguments.getOrDefault("wall-blocks", List.of()))) { + for (String blockStateStr : MiscUtils.getAsStringList(arguments.getOrDefault("attached-blocks", List.of()))) { int index = blockStateStr.indexOf('['); Key blockType = index != -1 ? Key.from(blockStateStr.substring(0, index)) : Key.from(blockStateStr); Material material = Registry.MATERIAL.get(new NamespacedKey(blockType.namespace(), blockType.value())); From 2f1ec1ee698c060c5122b6bc6ff5842f4ab77570 Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <972454774@qq.com> Date: Thu, 18 Sep 2025 23:50:08 +0800 Subject: [PATCH 016/125] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E7=BD=91=E7=BB=9C=E7=AE=A1=E7=90=86=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 10 +- .../bukkit/plugin/BukkitCraftEngine.java | 5 +- .../plugin/network/BukkitNetworkManager.java | 3133 ++++++++++++++++- .../plugin/network/PacketConsumers.java | 2703 -------------- .../handler/BlockDisplayPacketHandler.java | 9 +- .../handler/CommonItemPacketHandler.java | 2 +- .../handler/EndermanPacketHandler.java | 9 +- .../handler/MinecartPacketHandler.java | 16 +- .../handler/PrimedTNTPacketHandler.java | 9 +- .../plugin/network/id/PacketIdFinder.java | 75 - .../plugin/network/id/PacketIds1_20.java | 104 +- .../plugin/network/id/PacketIds1_20_5.java | 95 +- .../plugin/network/id/PlayPacketIdHelper.java | 61 + .../listener/ByteBufferPacketListener.java | 13 + .../network/listener/NMSPacketListener.java | 13 + .../core/plugin/network/NetworkManager.java | 2 + .../core/plugin/network/PacketFlow.java | 6 + gradle.properties | 12 +- 18 files changed, 3236 insertions(+), 3041 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListener.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/NMSPacketListener.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/network/PacketFlow.java 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 a63b539be..7dfe46fa0 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 @@ -10,7 +10,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BlockGenerator; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; @@ -102,7 +102,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { } this.stateId2ImmutableBlockStates = new ImmutableBlockState[this.customBlockCount]; Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.INSTANCE.defaultState()); - this.resetPacketConsumers(); + this.resetPacketListeners(); } @Override @@ -149,7 +149,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { @Override public void delayedLoad() { - this.resetPacketConsumers(); + this.resetPacketListeners(); super.delayedLoad(); } @@ -263,14 +263,14 @@ public final class BukkitBlockManager extends AbstractBlockManager { holder.bindValue(emptyBlock); } - private void resetPacketConsumers() { + private void resetPacketListeners() { Map finalMapping = new HashMap<>(this.blockAppearanceMapper); int stoneId = BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState); for (int custom : this.internalId2StateId.values()) { finalMapping.put(custom, stoneId); } finalMapping.putAll(this.tempBlockAppearanceConvertor); - PacketConsumers.initBlocks(finalMapping, RegistryUtils.currentBlockRegistrySize()); + BukkitNetworkManager.instance().registerBlockStatePacketListeners(finalMapping, RegistryUtils.currentBlockRegistrySize()); } private void initVanillaRegistry() { 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 6633b1fa3..e00b9b64b 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 @@ -20,12 +20,10 @@ import net.momirealms.craftengine.bukkit.plugin.command.BukkitSenderFactory; import net.momirealms.craftengine.bukkit.plugin.gui.BukkitGuiManager; import net.momirealms.craftengine.bukkit.plugin.injector.*; import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; import net.momirealms.craftengine.bukkit.plugin.scheduler.BukkitSchedulerAdapter; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.sound.BukkitSoundManager; import net.momirealms.craftengine.bukkit.util.EventUtils; -import net.momirealms.craftengine.bukkit.util.RegistryUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -146,8 +144,8 @@ public class BukkitCraftEngine extends CraftEngine { throw new InjectionException("Error initializing ProtectedFieldVisitor", e); } super.onPluginLoad(); - super.blockManager.init(); super.networkManager = new BukkitNetworkManager(this); + super.blockManager.init(); super.itemManager = new BukkitItemManager(this); this.successfullyLoaded = true; super.compatibilityManager().onLoad(); @@ -191,7 +189,6 @@ public class BukkitCraftEngine extends CraftEngine { BukkitItemBehaviors.init(); BukkitHitBoxTypes.init(); BukkitBlockEntityElementConfigs.init(); - PacketConsumers.initEntities(RegistryUtils.currentEntityTypeRegistrySize()); super.packManager = new BukkitPackManager(this); super.senderFactory = new BukkitSenderFactory(this); super.recipeManager = new BukkitRecipeManager(this); 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 f97d36b3e..370b57d79 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,30 +1,92 @@ 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; import io.netty.channel.*; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntList; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; +import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; +import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent; +import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; +import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; +import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; +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.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIdFinder; +import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor; +import net.momirealms.craftengine.bukkit.plugin.network.handler.*; +import net.momirealms.craftengine.bukkit.plugin.network.id.PlayPacketIdHelper; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20_5; +import net.momirealms.craftengine.bukkit.plugin.network.listener.ByteBufferPacketListener; +import net.momirealms.craftengine.bukkit.plugin.network.listener.NMSPacketListener; +import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; +import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; import net.momirealms.craftengine.bukkit.plugin.network.payload.PayloadHelper; +import net.momirealms.craftengine.bukkit.plugin.network.payload.UnknownPayload; import net.momirealms.craftengine.bukkit.plugin.reflection.leaves.LeavesReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.LibraryReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.*; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.plugin.user.FakeBukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; +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; +import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; +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; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.CooldownData; +import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext; +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.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.logger.Debugger; import net.momirealms.craftengine.core.plugin.network.*; +import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; import net.momirealms.craftengine.core.util.*; -import org.bukkit.Bukkit; +import net.momirealms.craftengine.core.world.*; +import net.momirealms.craftengine.core.world.chunk.CEChunk; +import net.momirealms.craftengine.core.world.chunk.ChunkStatus; +import net.momirealms.craftengine.core.world.chunk.Palette; +import net.momirealms.craftengine.core.world.chunk.PalettedContainer; +import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; +import net.momirealms.craftengine.core.world.chunk.packet.MCSection; +import net.momirealms.craftengine.core.world.collision.AABB; +import net.momirealms.sparrow.nbt.Tag; +import org.bukkit.*; +import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -32,49 +94,33 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.messaging.PluginMessageListener; +import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; public class BukkitNetworkManager implements NetworkManager, Listener, PluginMessageListener { 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_GAME_BYTE_BUFFER_PACKET_HANDLERS; - private static BiConsumer[] C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS; + private final BukkitCraftEngine plugin; + private final Map, NMSPacketListener> nmsPacketListeners = new IdentityHashMap<>(128); - private static void registerNMSPacketConsumer(final TriConsumer function, @Nullable Class packet) { - if (packet == null) return; - NMS_PACKET_HANDLERS.put(packet, function); - } - - private static void registerS2CByteBufPacketConsumer(final BiConsumer function, int id) { - if (id == -1) return; - if (id < 0 || id >= S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS.length) { - throw new IllegalArgumentException("Invalid packet id: " + id); - } - 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_GAME_BYTE_BUFFER_PACKET_HANDLERS.length) { - throw new IllegalArgumentException("Invalid packet id: " + id); - } - C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS[id] = function; - } + private final ByteBufferPacketListener[] s2cGamePacketListeners; + private final ByteBufferPacketListener[] c2sGamePacketListeners; private final TriConsumer packetConsumer; private final TriConsumer, Object> packetsConsumer; private final TriConsumer immediatePacketConsumer; private final TriConsumer, Runnable> immediatePacketsConsumer; - private final BukkitCraftEngine plugin; private final Map users = new ConcurrentHashMap<>(); private final Map onlineUsers = new ConcurrentHashMap<>(); @@ -89,23 +135,24 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static final String PACKET_ENCODER = "craftengine_encoder"; private static final String PACKET_DECODER = "craftengine_decoder"; - private static boolean hasModelEngine; - private static boolean hasViaVersion; + private final boolean hasModelEngine; + private final boolean hasViaVersion; + + private int[] blockStateRemapper; + private int[] modBlockStateRemapper; @SuppressWarnings("unchecked") public BukkitNetworkManager(BukkitCraftEngine plugin) { instance = this; - 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.s2cGamePacketListeners = new ByteBufferPacketListener[PlayPacketIdHelper.count(PacketFlow.CLIENTBOUND)]; + this.c2sGamePacketListeners = new ByteBufferPacketListener[PlayPacketIdHelper.count(PacketFlow.SERVERBOUND)]; + this.hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; + this.hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; this.plugin = plugin; // set up packet id this.packetIds = VersionHelper.isOrAbove1_20_5() ? new PacketIds1_20_5() : new PacketIds1_20(); // register packet handlers - this.registerPacketHandlers(); + this.registerPacketListeners(); PayloadHelper.registerDataTypes(); // set up packet senders this.packetConsumer = FastNMS.INSTANCE::method$Connection$send; @@ -156,6 +203,32 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes return instance; } + @Override + public int remapBlockState(int stateId, boolean enableMod) { + return enableMod ? this.modBlockStateRemapper[stateId] : this.blockStateRemapper[stateId]; + } + + private void registerNMSPacketConsumer(final NMSPacketListener listener, @Nullable Class packet) { + if (packet == null) return; + this.nmsPacketListeners.put(packet, listener); + } + + private void registerS2CGamePacketListener(final ByteBufferPacketListener function, int id) { + if (id == -1) return; + if (id < 0 || id >= this.s2cGamePacketListeners.length) { + throw new IllegalArgumentException("Invalid packet id: " + id); + } + this.s2cGamePacketListeners[id] = function; + } + + private void registerC2SGamePacketListener(final ByteBufferPacketListener function, int id) { + if (id == -1) return; + if (id < 0 || id >= this.c2sGamePacketListeners.length) { + throw new IllegalArgumentException("Invalid packet id: " + id); + } + this.c2sGamePacketListeners[id] = function; + } + public void addFakePlayer(Player player) { FakeBukkitServerPlayer fakePlayer = new FakeBukkitServerPlayer(this.plugin); fakePlayer.setPlayer(player); @@ -189,65 +262,138 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - private void registerPacketHandlers() { - registerNMSPacketConsumer(PacketConsumers.PLAYER_INFO_UPDATE, NetworkReflections.clazz$ClientboundPlayerInfoUpdatePacket); - registerNMSPacketConsumer(PacketConsumers.PLAYER_ACTION, NetworkReflections.clazz$ServerboundPlayerActionPacket); - registerNMSPacketConsumer(PacketConsumers.SWING_HAND, NetworkReflections.clazz$ServerboundSwingPacket); - registerNMSPacketConsumer(PacketConsumers.HELLO_C2S, NetworkReflections.clazz$ServerboundHelloPacket); - registerNMSPacketConsumer(PacketConsumers.USE_ITEM_ON, NetworkReflections.clazz$ServerboundUseItemOnPacket); - registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_BLOCK, NetworkReflections.clazz$ServerboundPickItemFromBlockPacket); - registerNMSPacketConsumer(PacketConsumers.SET_CREATIVE_SLOT, NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket); - registerNMSPacketConsumer(PacketConsumers.LOGIN, NetworkReflections.clazz$ClientboundLoginPacket); - registerNMSPacketConsumer(PacketConsumers.RESPAWN, NetworkReflections.clazz$ClientboundRespawnPacket); - registerNMSPacketConsumer(PacketConsumers.SYNC_ENTITY_POSITION, NetworkReflections.clazz$ClientboundEntityPositionSyncPacket); - registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, NetworkReflections.clazz$ServerboundPickItemFromEntityPacket); - registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, NetworkReflections.clazz$ServerboundRenameItemPacket); - registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, NetworkReflections.clazz$ServerboundSignUpdatePacket); - registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, NetworkReflections.clazz$ServerboundEditBookPacket); - registerNMSPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD_1_20_2, VersionHelper.isOrAbove1_20_2() ? NetworkReflections.clazz$ServerboundCustomPayloadPacket : null); - 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); - registerNMSPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_21_5, VersionHelper.isOrAbove1_21_5() ? NetworkReflections.clazz$ServerboundContainerClickPacket : null); - registerS2CByteBufPacketConsumer(PacketConsumers.FORGET_LEVEL_CHUNK, this.packetIds.clientboundForgetLevelChunkPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_21_4() ? PacketConsumers.LEVEL_PARTICLE_1_21_4 : (VersionHelper.isOrAbove1_20_5() ? PacketConsumers.LEVEL_PARTICLE_1_20_5 : PacketConsumers.LEVEL_PARTICLE_1_20), this.packetIds.clientboundLevelParticlesPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_EVENT, this.packetIds.clientboundLevelEventPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.OPEN_SCREEN_1_20_3 : PacketConsumers.OPEN_SCREEN_1_20, this.packetIds.clientboundOpenScreenPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_TITLE_TEXT_1_20_3 : PacketConsumers.SET_TITLE_TEXT_1_20, this.packetIds.clientboundSetTitleTextPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_SUBTITLE_TEXT_1_20_3 : PacketConsumers.SET_SUBTITLE_TEXT_1_20, this.packetIds.clientboundSetSubtitleTextPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_ACTIONBAR_TEXT_1_20_3 : PacketConsumers.SET_ACTIONBAR_TEXT_1_20, this.packetIds.clientboundSetActionBarTextPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.BOSS_EVENT_1_20_3 : PacketConsumers.BOSS_EVENT_1_20, this.packetIds.clientboundBossEventPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SYSTEM_CHAT_1_20_3 : PacketConsumers.SYSTEM_CHAT_1_20, this.packetIds.clientboundSystemChatPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TAB_LIST_1_20_3 : PacketConsumers.TAB_LIST_1_20, this.packetIds.clientboundTabListPacket()); - 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()); - registerS2CByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_SLOT, this.packetIds.clientboundContainerSetSlotPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SET_CURSOR_ITEM, this.packetIds.clientboundSetCursorItemPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SET_EQUIPMENT, this.packetIds.clientboundSetEquipmentPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY_1_21_2, this.packetIds.clientboundSetPlayerInventoryPacket()); - registerC2SByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); - registerC2SByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_20, VersionHelper.isOrAbove1_21_5() ? -1 : this.packetIds.serverboundContainerClickPacket()); - registerC2SByteBufPacketConsumer(PacketConsumers.INTERACT_ENTITY, this.packetIds.serverboundInteractPacket()); - registerC2SByteBufPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD_1_20, VersionHelper.isOrAbove1_20_2() ? -1 : this.packetIds.serverboundCustomPayloadPacket()); + public void registerBlockStatePacketListeners(Map map, int registrySize) { + int[] newMappings = new int[registrySize]; + for (int i = 0; i < registrySize; i++) { + newMappings[i] = i; + } + int[] newMappingsMOD = Arrays.copyOf(newMappings, registrySize); + for (Map.Entry entry : map.entrySet()) { + newMappings[entry.getKey()] = entry.getValue(); + if (BlockStateUtils.isVanillaBlock((int) entry.getKey())) { + newMappingsMOD[entry.getKey()] = entry.getValue(); + } + } + for (int i = 0; i < newMappingsMOD.length; i++) { + if (BlockStateUtils.isVanillaBlock(i)) { + newMappingsMOD[i] = newMappings[i]; + } + } + this.blockStateRemapper = newMappings; + this.modBlockStateRemapper = newMappingsMOD; + registerS2CGamePacketListener(new LevelChunkWithLightListener(newMappings, newMappingsMOD, registrySize, RegistryUtils.currentBiomeRegistrySize()), this.packetIds.clientboundLevelChunkWithLightPacket()); + registerS2CGamePacketListener(new SectionBlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundSectionBlocksUpdatePacket()); + registerS2CGamePacketListener(new BlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundBlockUpdatePacket()); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_21_4() ? + new LevelParticleListener1_21_4(newMappings, newMappingsMOD) : + (VersionHelper.isOrAbove1_20_5() ? + new LevelParticleListener1_20_5(newMappings, newMappingsMOD) : + new LevelParticleListener1_20(newMappings, newMappingsMOD)), + this.packetIds.clientboundLevelParticlesPacket() + ); + registerS2CGamePacketListener(new LevelEventListener(newMappings, newMappingsMOD), this.packetIds.clientboundLevelEventPacket()); + } + + private void registerPacketListeners() { + registerNMSPacketConsumer(new PlayerInfoUpdateListener(), NetworkReflections.clazz$ClientboundPlayerInfoUpdatePacket); + registerNMSPacketConsumer(new PlayerActionListener(), NetworkReflections.clazz$ServerboundPlayerActionPacket); + registerNMSPacketConsumer(new SwingListener(), NetworkReflections.clazz$ServerboundSwingPacket); + registerNMSPacketConsumer(new HelloListener(), NetworkReflections.clazz$ServerboundHelloPacket); + registerNMSPacketConsumer(new UseItemOnListener(), NetworkReflections.clazz$ServerboundUseItemOnPacket); + registerNMSPacketConsumer(new PickItemFromBlockListener(), NetworkReflections.clazz$ServerboundPickItemFromBlockPacket); + registerNMSPacketConsumer(new PickItemFromEntityListener(), NetworkReflections.clazz$ServerboundPickItemFromEntityPacket); + registerNMSPacketConsumer(new SetCreativeSlotListener(), NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket); + registerNMSPacketConsumer(new LoginListener(), NetworkReflections.clazz$ClientboundLoginPacket); + registerNMSPacketConsumer(new RespawnListener(), NetworkReflections.clazz$ClientboundRespawnPacket); + registerNMSPacketConsumer(new SyncEntityPositionListener(), NetworkReflections.clazz$ClientboundEntityPositionSyncPacket); + registerNMSPacketConsumer(new RenameItemListener(), NetworkReflections.clazz$ServerboundRenameItemPacket); + registerNMSPacketConsumer(new SignUpdateListener(), NetworkReflections.clazz$ServerboundSignUpdatePacket); + registerNMSPacketConsumer(new EditBookListener(), NetworkReflections.clazz$ServerboundEditBookPacket); + registerNMSPacketConsumer(new CustomPayloadListener1_20_2(), VersionHelper.isOrAbove1_20_2() ? NetworkReflections.clazz$ServerboundCustomPayloadPacket : null); + registerNMSPacketConsumer(new ResourcePackResponseListener(), NetworkReflections.clazz$ServerboundResourcePackPacket); + registerNMSPacketConsumer(new EntityEventListener(), NetworkReflections.clazz$ClientboundEntityEventPacket); + registerNMSPacketConsumer(new MovePosAndRotateEntityListener(), NetworkReflections.clazz$ClientboundMoveEntityPacket$PosRot); + registerNMSPacketConsumer(new MovePosEntityListener(), NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos); + registerNMSPacketConsumer(new RotateHeadListener(), NetworkReflections.clazz$ClientboundRotateHeadPacket); + registerNMSPacketConsumer(new SetEntityMotionListener(), NetworkReflections.clazz$ClientboundSetEntityMotionPacket); + registerNMSPacketConsumer(new FinishConfigurationListener(), NetworkReflections.clazz$ClientboundFinishConfigurationPacket); + registerNMSPacketConsumer(new LoginFinishedListener(), NetworkReflections.clazz$ClientboundLoginFinishedPacket); + registerNMSPacketConsumer(new UpdateTagsListener(), NetworkReflections.clazz$ClientboundUpdateTagsPacket); + registerNMSPacketConsumer(new ContainerClickListener1_21_5(), VersionHelper.isOrAbove1_21_5() ? NetworkReflections.clazz$ServerboundContainerClickPacket : null); + registerS2CGamePacketListener(new ForgetLevelChunkListener(), this.packetIds.clientboundForgetLevelChunkPacket()); + registerS2CGamePacketListener(new SetScoreListener1_20_3(), VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1); + registerS2CGamePacketListener(new AddRecipeBookListener(), this.packetIds.clientboundRecipeBookAddPacket()); + registerS2CGamePacketListener(new PlaceGhostRecipeListener(), this.packetIds.clientboundPlaceGhostRecipePacket()); + registerS2CGamePacketListener(new UpdateRecipesListener(), this.packetIds.clientboundUpdateRecipesPacket()); + registerS2CGamePacketListener(new UpdateAdvancementsListener(), this.packetIds.clientboundUpdateAdvancementsPacket()); + registerS2CGamePacketListener(new RemoveEntityListener(), this.packetIds.clientboundRemoveEntitiesPacket()); + registerS2CGamePacketListener(new SoundListener(), this.packetIds.clientboundSoundPacket()); + registerS2CGamePacketListener(new ContainerSetContentListener(), this.packetIds.clientboundContainerSetContentPacket()); + registerS2CGamePacketListener(new ContainerSetSlotListener(), this.packetIds.clientboundContainerSetSlotPacket()); + registerS2CGamePacketListener(new SetCursorItemListener(), this.packetIds.clientboundSetCursorItemPacket()); + registerS2CGamePacketListener(new SetEquipmentListener(), this.packetIds.clientboundSetEquipmentPacket()); + registerS2CGamePacketListener(new SetPlayerInventoryListener1_21_2(), VersionHelper.isOrAbove1_21_2() ? this.packetIds.clientboundSetPlayerInventoryPacket() : -1); + registerS2CGamePacketListener(new SetEntityDataListener(), this.packetIds.clientboundSetEntityDataPacket()); + registerC2SGamePacketListener(new SetCreativeModeSlotListener(), this.packetIds.serverboundSetCreativeModeSlotPacket()); + registerC2SGamePacketListener(new ContainerClick1_20(), VersionHelper.isOrAbove1_21_5() ? -1 : this.packetIds.serverboundContainerClickPacket()); + registerC2SGamePacketListener(new InteractEntityListener(), this.packetIds.serverboundInteractPacket()); + registerC2SGamePacketListener(new CustomPayloadListener1_20(), VersionHelper.isOrAbove1_20_2() ? -1 : this.packetIds.serverboundCustomPayloadPacket()); + registerS2CGamePacketListener(new AddEntityListener(RegistryUtils.currentEntityTypeRegistrySize()), this.packetIds.clientboundAddEntityPacket()); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new OpenScreenListener1_20_3() : + new OpenScreenListener1_20(), + this.packetIds.clientboundOpenScreenPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SystemChatListener1_20_3() : + new SystemChatListener1_20(), + this.packetIds.clientboundSystemChatPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SetActionBarListener1_20_3() : + new SetActionBarListener1_20(), + this.packetIds.clientboundSetActionBarTextPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new TabListListener1_20_3() : + new TabListListener1_20(), + this.packetIds.clientboundTabListPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SetTitleListener1_20_3() : + new SetTitleListener1_20(), + this.packetIds.clientboundSetTitleTextPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SetSubtitleListener1_20_3() : + new SetSubtitleListener1_20(), + this.packetIds.clientboundSetSubtitleTextPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new BossEventListener1_20_3() : + new BossEventListener1_20(), + this.packetIds.clientboundBossEventPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new TeamListener1_20_3() : + new TeamListener1_20(), + this.packetIds.clientboundSetPlayerTeamPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SetObjectiveListener1_20_3() : + new SetObjectiveListener1_20(), + this.packetIds.clientboundSetObjectivePacket() + ); } @EventHandler(priority = EventPriority.LOWEST) @@ -383,11 +529,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - public static boolean hasModelEngine() { + public boolean hasModelEngine() { return hasModelEngine; } - public static boolean hasViaVersion() { + public boolean hasViaVersion() { return hasViaVersion; } @@ -709,7 +855,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); + handleReceiveNMSPacket(user, event, packet); } private void onNMSPacketSend(NetWorkUser player, NMSPacketEvent event, Object packet) { @@ -720,25 +866,54 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } else { Debugger.PACKET.debug(() -> "[S->C]" + packet.getClass()); - handleNMSPacket(player, event, packet); + handleSendNMSPacket(player, event, packet); } } - protected void handleNMSPacket(NetWorkUser user, NMSPacketEvent event, Object packet) { - Optional.ofNullable(NMS_PACKET_HANDLERS.get(packet.getClass())) - .ifPresent(function -> function.accept(user, event, packet)); + protected void handleReceiveNMSPacket(NetWorkUser user, NMSPacketEvent event, Object packet) { + NMSPacketListener nmsPacketListener = this.nmsPacketListeners.get(packet.getClass()); + if (nmsPacketListener != null) { + try { + nmsPacketListener.onPacketReceive(user, event, packet); + } catch (Throwable t) { + this.plugin.logger().warn("An error occurred when handling packet " + packet.getClass(), t); + } + } + } + + protected void handleSendNMSPacket(NetWorkUser user, NMSPacketEvent event, Object packet) { + NMSPacketListener nmsPacketListener = this.nmsPacketListeners.get(packet.getClass()); + if (nmsPacketListener != null) { + try { + nmsPacketListener.onPacketSend(user, event, packet); + } catch (Throwable t) { + this.plugin.logger().warn("An error occurred when handling packet " + packet.getClass(), t); + } + } } protected void handleS2CByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS[packetID]) - .ifPresent(function -> function.accept(user, event)); + ByteBufferPacketListener s2cGamePacketListener = this.s2cGamePacketListeners[packetID]; + if (s2cGamePacketListener != null) { + try { + s2cGamePacketListener.onPacketSend(user, event); + } catch (Throwable t) { + this.plugin.logger().warn("An error occurred when handling sent packet id: " + packetID, t); + } + } } protected void handleC2SByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS[packetID]) - .ifPresent(function -> function.accept(user, event)); + ByteBufferPacketListener c2sGamePacketListener = this.c2sGamePacketListeners[packetID]; + if (c2sGamePacketListener != null) { + try { + c2sGamePacketListener.onPacketReceive(user, event); + } catch (Throwable t) { + this.plugin.logger().warn("An error occurred when handling received packet id: " + packetID, t); + } + } } private void compress(ChannelHandlerContext ctx, ByteBuf input) { @@ -784,13 +959,2741 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes return output; } - @FunctionalInterface - public interface Handlers extends BiConsumer { - Handlers DO_NOTHING = doNothing(); + /* + * + * + * Packet Listener Implementations + * + * + */ + public static class HelloListener implements NMSPacketListener { - static Handlers doNothing() { - return (user, byteBufPacketEvent) -> { + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + String name; + try { + name = (String) NetworkReflections.methodHandle$ServerboundHelloPacket$nameGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().severe("Failed to get name from ServerboundHelloPacket", t); + return; + } + player.setUnverifiedName(name); + if (VersionHelper.isOrAbove1_20_2()) { + UUID uuid; + try { + uuid = (UUID) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().severe("Failed to get uuid from ServerboundHelloPacket", t); + return; + } + player.setUnverifiedUUID(uuid); + } else { + Optional uuid; + try { + // noinspection unchecked + uuid = (Optional) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().severe("Failed to get uuid from ServerboundHelloPacket", t); + return; + } + if (uuid.isPresent()) { + player.setUnverifiedUUID(uuid.get()); + } else { + player.setUnverifiedUUID(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8))); + } + } + } + } + + public static class PlayerActionListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + Player platformPlayer = player.platformPlayer(); + World world = platformPlayer.getWorld(); + Object blockPos = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$pos(packet); + BlockPos pos = LocationUtils.fromBlockPos(blockPos); + if (VersionHelper.isFolia()) { + platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { + try { + handlePlayerActionPacketOnMainThread(player, world, pos, packet); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPlayerActionPacket", e); + } + }, () -> {}); + } else { + handlePlayerActionPacketOnMainThread(player, world, pos, packet); + } + } + + private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) { + Object action = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$action(packet); + if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) { + Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, LocationUtils.toBlockPos(pos)); + int stateId = BlockStateUtils.blockStateToId(blockState); + // not a custom block + if (BlockStateUtils.isVanillaBlock(stateId)) { + if (Config.enableSoundSystem()) { + Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState); + if (BukkitBlockManager.instance().isBlockSoundRemoved(blockOwner)) { + player.startMiningBlock(pos, blockState, null); + return; + } + } + if (player.isMiningBlock()) { + player.stopMiningBlock(); + } else { + player.setClientSideCanBreakBlock(true); + } + return; + } + if (player.isAdventureMode()) { + if (Config.simplifyAdventureBreakCheck()) { + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); + if (!player.canBreak(pos, state.vanillaBlockState().literalObject())) { + player.preventMiningBlock(); + return; + } + } else { + if (!player.canBreak(pos, null)) { + player.preventMiningBlock(); + return; + } + } + } + player.startMiningBlock(pos, blockState, BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId)); + } else if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$ABORT_DESTROY_BLOCK) { + if (player.isMiningBlock()) { + player.abortMiningBlock(); + } + } else if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$STOP_DESTROY_BLOCK) { + if (player.isMiningBlock()) { + player.stopMiningBlock(); + } + } + } + } + + public static class SwingListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + if (!player.isMiningBlock()) return; + Object hand = FastNMS.INSTANCE.field$ServerboundSwingPacket$hand(packet); + if (hand == CoreReflections.instance$InteractionHand$MAIN_HAND) { + player.onSwingHand(); + } + } + } + + public static class UseItemOnListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + if (player.isMiningBlock()) { + player.stopMiningBlock(); + } + } + } + + public static class PlayerInfoUpdateListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!Config.interceptPlayerInfo()) return; + List entries = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$entries(packet); + if (entries instanceof MarkedArrayList) { + return; + } + EnumSet> enums = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$actions(packet); + outer: { + for (Object entry : enums) { + if (entry == NetworkReflections.instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME) { + break outer; + } + } + return; + } + boolean isChanged = false; + List newEntries = new MarkedArrayList<>(); + for (Object entry : entries) { + Object mcComponent = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$Entry$displayName(entry); + if (mcComponent == null) { + newEntries.add(entry); + } else { + String json = ComponentUtils.minecraftToJson(mcComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) { + newEntries.add(entry); + } else { + Object newEntry = FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket$Entry(entry, + ComponentUtils.adventureToMinecraft(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + newEntries.add(newEntry); + isChanged = true; + } + } + } + if (isChanged) { + event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket(enums, newEntries)); + } + } + } + + public static class PickItemFromBlockListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + Player player = (Player) user.platformPlayer(); + if (player == null) return; + Object pos; + try { + pos = NetworkReflections.methodHandle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to get pos from ServerboundPickItemFromBlockPacket", e); + return; + } + if (VersionHelper.isFolia()) { + int x = FastNMS.INSTANCE.field$Vec3i$x(pos); + int z = FastNMS.INSTANCE.field$Vec3i$z(pos); + BukkitCraftEngine.instance().scheduler().sync().run(() -> { + try { + handlePickItemFromBlockPacketOnMainThread(player, pos); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket on region thread", e); + } + }, player.getWorld(), x >> 4, z >> 4); + } else { + BukkitCraftEngine.instance().scheduler().sync().run(() -> { + try { + handlePickItemFromBlockPacketOnMainThread(player, pos); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket on main thread", e); + } + }); + } + } + + private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Throwable { + Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos); + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (state == null) return; + Key itemId = state.settings().itemId(); + if (itemId == null) return; + pickItem(player, itemId, pos, null); + } + } + + public static class PickItemFromEntityListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId; + try { + entityId = (int) NetworkReflections.methodHandle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to get entityId from ServerboundPickItemFromEntityPacket", e); + return; + } + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); + if (furniture == null) return; + Player player = (Player) user.platformPlayer(); + if (player == null) return; + if (VersionHelper.isFolia()) { + player.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { + try { + handlePickItemFromEntityOnMainThread(player, furniture); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket on region thread", e); + } + }, () -> {}); + } else { + BukkitCraftEngine.instance().scheduler().sync().run(() -> { + try { + handlePickItemFromEntityOnMainThread(player, furniture); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket on main thread", e); + } + }); + } + } + + private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Throwable { + Key itemId = furniture.config().settings().itemId(); + if (itemId == null) return; + pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity())); + } + } + + private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws Throwable { + ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, BukkitCraftEngine.instance().adapt(player)); + if (itemStack == null) { + CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); + return; + } + assert CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem != null; + if (VersionHelper.isOrAbove1_21_5()) { + CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( + CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), + FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true); + } else { + CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( + CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); + } + } + + + public static class SetCreativeSlotListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (VersionHelper.isOrAbove1_21_4()) return; + if (!user.isOnline()) return; + BukkitServerPlayer player = (BukkitServerPlayer) user; + if (VersionHelper.isFolia()) { + player.platformPlayer().getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { + try { + handleSetCreativeSlotPacketOnMainThread(player, packet); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket on region thread", e); + } + }, () -> {}); + } else { + try { + handleSetCreativeSlotPacketOnMainThread(player, packet); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket on main thread", e); + } + } + } + + private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Throwable { + Player bukkitPlayer = player.platformPlayer(); + if (bukkitPlayer == null) return; + if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return; + int slot = VersionHelper.isOrAbove1_20_5() ? (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 (ItemStackUtils.isEmpty(item)) return; + if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) { + return; + } + double interactionRange = player.getCachedInteractionRange(); + // do ray trace to get current block + RayTraceResult result = bukkitPlayer.rayTraceBlocks(interactionRange, FluidCollisionMode.NEVER); + if (result == null) return; + Block hitBlock = result.getHitBlock(); + if (hitBlock == null) return; + ImmutableBlockState state = CraftEngineBlocks.getCustomBlockState(hitBlock); + // not a custom block + if (state == null || state.isEmpty()) return; + Key itemId = state.settings().itemId(); + // no item available + if (itemId == null) return; + Object vanillaBlock = FastNMS.INSTANCE.method$BlockState$getBlock(state.vanillaBlockState().literalObject()); + 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 (ItemStackUtils.isEmpty(itemStack)) { + CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); + return; + } + PlayerInventory inventory = bukkitPlayer.getInventory(); + int sameItemSlot = -1; + int emptySlot = -1; + for (int i = 0; i < 9 + 27; i++) { + ItemStack invItem = inventory.getItem(i); + if (ItemStackUtils.isEmpty(invItem)) { + if (emptySlot == -1 && i < 9) emptySlot = i; + continue; + } + if (invItem.getType().equals(itemStack.getType()) && invItem.getItemMeta().equals(itemStack.getItemMeta())) { + if (sameItemSlot == -1) sameItemSlot = i; + } + } + if (sameItemSlot != -1) { + if (sameItemSlot < 9) { + inventory.setHeldItemSlot(sameItemSlot); + ItemStack previousItem = inventory.getItem(slot - 36); + BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, previousItem)); + } else { + ItemStack sameItem = inventory.getItem(sameItemSlot); + int finalSameItemSlot = sameItemSlot; + BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> { + inventory.setItem(finalSameItemSlot, new ItemStack(Material.AIR)); + inventory.setItem(slot - 36, sameItem); + }); + } + } else { + if (item.getAmount() == 1) { + if (ItemStackUtils.isEmpty(inventory.getItem(slot - 36))) { + BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack)); + return; + } + if (emptySlot != -1) { + inventory.setHeldItemSlot(emptySlot); + inventory.setItem(emptySlot, itemStack); + } else { + BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack)); + } + } + } + } + } + + public static class LoginListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + player.setConnectionState(ConnectionState.PLAY); + Object dimensionKey; + try { + if (!VersionHelper.isOrAbove1_20_2()) { + dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet); + } else { + Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); + } + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get dimensionKey from ClientboundLoginPacket", t); + return; + } + Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); + World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); + if (world != null) { + int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16; + player.setClientSideSectionCount(sectionCount); + player.setClientSideDimension(Key.of(location.toString())); + } else { + CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket: World " + location + " does not exist"); + } + } + } + + public static class RespawnListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + player.clearView(); + Object dimensionKey; + try { + if (!VersionHelper.isOrAbove1_20_2()) { + dimensionKey = NetworkReflections.methodHandle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet); + } else { + Object commonInfo = NetworkReflections.methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); + } + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get dimensionKey from ClientboundRespawnPacket", t); + return; + } + Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); + World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); + if (world != null) { + int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16; + player.setClientSideSectionCount(sectionCount); + player.setClientSideDimension(Key.of(location.toString())); + player.clearTrackedChunks(); + } else { + CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist"); + } + } + } + + // 1.21.2+ + public static class SyncEntityPositionListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleSyncEntityPosition(user, event, packet); + } + } + } + + public static class RenameItemListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!Config.filterAnvil()) return; + if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) { + return; + } + String message; + try { + message = (String) NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get message from ServerboundRenameItemPacket", t); + return; + } + if (message != null && !message.isEmpty()) { + // check bypass + FontManager manager = CraftEngine.instance().fontManager(); + IllegalCharacterProcessResult result = manager.processIllegalCharacters(message); + if (result.has()) { + try { + NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text()); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to set field 'name' for ServerboundRenameItemPacket", e); + } + } + } + } + } + + public static class SignUpdateListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!Config.filterSign()) return; + // check bypass + if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) { + return; + } + String[] lines; + try { + lines = (String[]) NetworkReflections.methodHandle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get lines from ServerboundSignUpdatePacket", t); + return; + } + FontManager manager = CraftEngine.instance().fontManager(); + if (!manager.isDefaultFontInUse()) return; + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + if (line != null && !line.isEmpty()) { + IllegalCharacterProcessResult result = manager.processIllegalCharacters(line); + if (result.has()) { + lines[i] = result.text(); + } + } + } + } + } + + public static class EditBookListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!Config.filterBook()) return; + FontManager manager = CraftEngine.instance().fontManager(); + if (!manager.isDefaultFontInUse()) return; + // check bypass + if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_BOOK)) { + return; + } + + boolean changed = false; + + List pages; + try { + // noinspection unchecked + pages = (List) NetworkReflections.methodHandle$ServerboundEditBookPacket$pagesGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get pages from ServerboundEditBookPacket", t); + return; + } + List newPages = new ArrayList<>(pages.size()); + Optional title; + try { + // noinspection unchecked + title = (Optional) NetworkReflections.methodHandle$ServerboundEditBookPacket$titleGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get title from ServerboundEditBookPacket", t); + return; + } + Optional newTitle; + + if (title.isPresent()) { + String titleStr = title.get(); + Pair result = processClientString(titleStr, manager); + newTitle = Optional.of(result.right()); + if (result.left()) { + changed = true; + } + } else { + newTitle = Optional.empty(); + } + + for (String page : pages) { + Pair result = processClientString(page, manager); + newPages.add(result.right()); + if (result.left()) { + changed = true; + } + } + + if (changed) { + try { + Object newPacket = NetworkReflections.constructor$ServerboundEditBookPacket.newInstance( + (int) NetworkReflections.methodHandle$ServerboundEditBookPacket$slotGetter.invokeExact(packet), + newPages, + newTitle + ); + event.replacePacket(newPacket); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to construct ServerboundEditBookPacket", t); + } + } + } + + private static Pair processClientString(String original, FontManager manager) { + if (original.isEmpty()) { + return Pair.of(false, original); + } + int[] codepoints = CharacterUtils.charsToCodePoints(original.toCharArray()); + int[] newCodepoints = new int[codepoints.length]; + boolean hasIllegal = false; + for (int i = 0; i < codepoints.length; i++) { + int codepoint = codepoints[i]; + if (manager.isIllegalCodepoint(codepoint)) { + newCodepoints[i] = '*'; + hasIllegal = true; + } else { + newCodepoints[i] = codepoint; + } + } + return hasIllegal ? Pair.of(true, new String(newCodepoints, 0, newCodepoints.length)) : Pair.of(false, original); + } + } + + public static class CustomPayloadListener1_20_2 implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!VersionHelper.isOrAbove1_20_2()) return; + Object payload; + try { + payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get payload from ServerboundCustomPayloadPacket", t); + return; + } + Payload clientPayload; + if (VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { + clientPayload = DiscardedPayload.from(payload); + } else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$ServerboundCustomPayloadPacket$UnknownPayload.isInstance(payload)) { + clientPayload = UnknownPayload.from(payload); + } else { + return; + } + if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return; + PayloadHelper.handleReceiver(clientPayload, user); + } + } + + public static class ResourcePackResponseListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + 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 (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); + } + }); + } + } + } + + public static class EntityEventListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + Object player = user.serverPlayer(); + if (player == null) return; + int entityId; + try { + entityId = (int) NetworkReflections.methodHandle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundEntityEventPacket", t); + return; + } + if (entityId != FastNMS.INSTANCE.method$Entity$getId(player)) return; + byte eventId; + try { + eventId = (byte) NetworkReflections.methodHandle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get event id from ClientboundEntityEventPacket", t); + return; + } + if (eventId >= 24 && eventId <= 28) { + CraftEngine.instance().fontManager().refreshEmojiSuggestions(user.uuid()); + } + } + } + + public static class MovePosAndRotateEntityListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); + if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { + event.setCancelled(true); + } + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleMoveAndRotate(user, event, packet); + } + } + } + + public static class MovePosEntityListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleMove(user, event, packet); + } + } + } + + public static class RotateHeadListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId; + try { + entityId = (int) NetworkReflections.methodHandle$ClientboundRotateHeadPacket$entityIdGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundRotateHeadPacket", t); + return; + } + if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { + event.setCancelled(true); + } + } + } + + public static class SetEntityMotionListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!VersionHelper.isOrAbove1_21_6()) return; + int entityId; + try { + entityId = (int) NetworkReflections.methodHandle$ClientboundSetEntityMotionPacket$idGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundSetEntityMotionPacket", t); + return; + } + if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { + event.setCancelled(true); + } + } + } + + public static class FinishConfigurationListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + 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); + + // 检查用户UUID是否已经校验 + if (!user.isUUIDVerified()) { + if (Config.strictPlayerUuidValidation()) { + TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString()); + user.kick(Component.translatable("disconnect.loginFailedInfo").arguments(Component.translatable("argument.uuid.invalid"))); + return; + } + if (Config.debugResourcePack()) { + TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString()); + } + } + + // 取消 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包 + try { + CoreReflections.methodHandle$ServerCommonPacketListenerImpl$closedSetter.invokeExact(packetListener, false); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to set the 'closed' field of ServerCommonPacketListenerImpl for" + user.name(), e); + } + } + + // 请求资源包 + 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 { + // noinspection unchecked + 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); + }); + } + } + + public static class LoginFinishedListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + GameProfile gameProfile = FastNMS.INSTANCE.field$ClientboundLoginFinishedPacket$gameProfile(packet); + user.setVerifiedName(gameProfile.getName()); + user.setVerifiedUUID(gameProfile.getId()); + } + } + + public static class UpdateTagsListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + Object modifiedPacket = BukkitBlockManager.instance().cachedUpdateTagsPacket(); + if (packet.equals(modifiedPacket) || modifiedPacket == null) return; + event.replacePacket(modifiedPacket); + } + } + + public static class ContainerClickListener1_21_5 implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + int containerId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$containerId(packet); + int stateId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$stateId(packet); + short slotNum = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$slotNum(packet); + byte buttonNum = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$buttonNum(packet); + Object clickType = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$clickType(packet); + @SuppressWarnings("unchecked") + Int2ObjectMap changedSlots = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$changedSlots(packet); + Int2ObjectMap newChangedSlots = new Int2ObjectOpenHashMap<>(changedSlots.size()); + for (Int2ObjectMap.Entry entry : changedSlots.int2ObjectEntrySet()) { + newChangedSlots.put(entry.getIntKey(), FastNMS.INSTANCE.constructor$InjectedHashedStack(entry.getValue(), player)); + } + Object carriedItem = FastNMS.INSTANCE.constructor$InjectedHashedStack(FastNMS.INSTANCE.field$ServerboundContainerClickPacket$carriedItem(packet), player); + event.replacePacket(FastNMS.INSTANCE.constructor$ServerboundContainerClickPacket(containerId, stateId, slotNum, buttonNum, clickType, Int2ObjectMaps.unmodifiable(newChangedSlots), carriedItem)); + } + } + + public static class ForgetLevelChunkListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + FriendlyByteBuf buf = event.getBuffer(); + CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid()); + if (VersionHelper.isOrAbove1_20_2()) { + long chunkPos = buf.readLong(); + user.removeTrackedChunk(chunkPos); + CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos); + if (ceChunk != null) { + ceChunk.despawnBlockEntities(player); + } + } else { + int x = buf.readInt(); + int y = buf.readInt(); + user.removeTrackedChunk(ChunkPos.asLong(x, y)); + CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(x, y); + if (ceChunk != null) { + ceChunk.despawnBlockEntities(player); + } + } + } + } + + public static class LevelChunkWithLightListener implements ByteBufferPacketListener { + private static BiConsumer> biomeRemapper = null; + + public static void setBiomeRemapper(BiConsumer> remapper) { + biomeRemapper = remapper; + } + + public static void remapBiomes(NetWorkUser user, PalettedContainer biomes) { + if (biomeRemapper != null) { + biomeRemapper.accept(user, biomes); + } + } + + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + private final IntIdentityList biomeList; + private final IntIdentityList blockList; + + public LevelChunkWithLightListener(int[] blockStateMapper, int[] modBlockStateMapper, int blockRegistrySize, int biomeRegistrySize) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + this.biomeList = new IntIdentityList(biomeRegistrySize); + this.blockList = new IntIdentityList(blockRegistrySize); + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + FriendlyByteBuf buf = event.getBuffer(); + int chunkX = buf.readInt(); + int chunkZ = buf.readInt(); + boolean named = !VersionHelper.isOrAbove1_20_2(); + // ClientboundLevelChunkPacketData + int heightmapsCount = 0; + Map heightmapsMap = null; + net.momirealms.sparrow.nbt.Tag heightmaps = null; + if (VersionHelper.isOrAbove1_21_5()) { + heightmapsMap = new HashMap<>(); + heightmapsCount = buf.readVarInt(); + for (int i = 0; i < heightmapsCount; i++) { + int key = buf.readVarInt(); + long[] value = buf.readLongArray(); + heightmapsMap.put(key, value); + } + } else { + heightmaps = buf.readNbt(named); + } + + int varInt = buf.readVarInt(); + byte[] buffer = new byte[varInt]; + buf.readBytes(buffer); + int blockEntitiesDataCount = buf.readVarInt(); + List blockEntitiesData = new ArrayList<>(); + for (int i = 0; i < blockEntitiesDataCount; i++) { + byte packedXZ = buf.readByte(); + short y = buf.readShort(); + int type = buf.readVarInt(); + Tag tag = buf.readNbt(named); + BlockEntityData blockEntityData = new BlockEntityData(packedXZ, y, type, tag); + blockEntitiesData.add(blockEntityData); + } + // ClientboundLightUpdatePacketData + BitSet skyYMask = buf.readBitSet(); + BitSet blockYMask = buf.readBitSet(); + BitSet emptySkyYMask = buf.readBitSet(); + BitSet emptyBlockYMask = buf.readBitSet(); + List skyUpdates = buf.readByteArrayList(2048); + List blockUpdates = buf.readByteArrayList(2048); + // 开始处理 + if (user.clientModEnabled()) { + ByteBuf byteBuf = Unpooled.copiedBuffer(buffer); + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); + FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); + for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { + MCSection mcSection = new MCSection(user.clientBlockList(), this.blockList, this.biomeList); + mcSection.readPacket(friendlyByteBuf); + PalettedContainer container = mcSection.blockStateContainer(); + remapBiomes(user, mcSection.biomeContainer()); + Palette palette = container.data().palette(); + if (palette.canRemap()) { + palette.remap(s -> this.modBlockStateMapper[s]); + } else { + for (int j = 0; j < 4096; j++) { + int state = container.get(j); + int newState = this.modBlockStateMapper[state]; + if (newState != state) { + container.set(j, newState); + } + } + } + mcSection.writePacket(newBuf); + } + buffer = newBuf.array(); + } else { + ByteBuf byteBuf = Unpooled.copiedBuffer(buffer); + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); + FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); + for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { + MCSection mcSection = new MCSection(user.clientBlockList(), this.blockList, this.biomeList); + mcSection.readPacket(friendlyByteBuf); + PalettedContainer container = mcSection.blockStateContainer(); + remapBiomes(user, mcSection.biomeContainer()); + Palette palette = container.data().palette(); + if (palette.canRemap()) { + palette.remap(s -> this.blockStateMapper[s]); + } else { + for (int j = 0; j < 4096; j++) { + int state = container.get(j); + int newState = this.blockStateMapper[state]; + if (newState != state) { + container.set(j, newState); + } + } + } + mcSection.writePacket(newBuf); + } + buffer = newBuf.array(); + } + + // 开始修改 + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeInt(chunkX); + buf.writeInt(chunkZ); + if (VersionHelper.isOrAbove1_21_5()) { + buf.writeVarInt(heightmapsCount); + for (Map.Entry entry : heightmapsMap.entrySet()) { + buf.writeVarInt(entry.getKey()); + buf.writeLongArray(entry.getValue()); + } + } else { + buf.writeNbt(heightmaps, named); + } + buf.writeVarInt(buffer.length); + buf.writeBytes(buffer); + buf.writeVarInt(blockEntitiesDataCount); + for (BlockEntityData blockEntityData : blockEntitiesData) { + buf.writeByte(blockEntityData.packedXZ()); + buf.writeShort(blockEntityData.y()); + buf.writeVarInt(blockEntityData.type()); + buf.writeNbt(blockEntityData.tag(), named); + } + buf.writeBitSet(skyYMask); + buf.writeBitSet(blockYMask); + buf.writeBitSet(emptySkyYMask); + buf.writeBitSet(emptyBlockYMask); + buf.writeByteArrayList(skyUpdates); + buf.writeByteArrayList(blockUpdates); + + ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); + // 记录加载的区块 + player.addTrackedChunk(chunkPos.longKey, new ChunkStatus()); + + CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid()); + CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos.longKey); + if (ceChunk != null) { + ceChunk.spawnBlockEntities(player); + } + } + } + + public static class SectionBlockUpdateListener implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public SectionBlockUpdateListener(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (user.clientModEnabled()) { + FriendlyByteBuf buf = event.getBuffer(); + long pos = buf.readLong(); + int blocks = buf.readVarInt(); + short[] positions = new short[blocks]; + int[] states = new int[blocks]; + for (int i = 0; i < blocks; i++) { + long k = buf.readVarLong(); + positions[i] = (short) ((int) (k & 4095L)); + states[i] = modBlockStateMapper[((int) (k >>> 12))]; + } + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeLong(pos); + buf.writeVarInt(blocks); + for (int i = 0; i < blocks; i++) { + buf.writeVarLong((long) states[i] << 12 | positions[i]); + } + event.setChanged(true); + } else { + FriendlyByteBuf buf = event.getBuffer(); + long pos = buf.readLong(); + int blocks = buf.readVarInt(); + short[] positions = new short[blocks]; + int[] states = new int[blocks]; + for (int i = 0; i < blocks; i++) { + long k = buf.readVarLong(); + positions[i] = (short) ((int) (k & 4095L)); + states[i] = blockStateMapper[((int) (k >>> 12))]; + } + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeLong(pos); + buf.writeVarInt(blocks); + for (int i = 0; i < blocks; i++) { + buf.writeVarLong((long) states[i] << 12 | positions[i]); + } + event.setChanged(true); + } + } + } + + public static class BlockUpdateListener implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public BlockUpdateListener(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + BlockPos pos = buf.readBlockPos(); + int before = buf.readVarInt(); + if (user.clientModEnabled() && !BlockStateUtils.isVanillaBlock(before)) { + return; + } + int state = user.clientModEnabled() ? modBlockStateMapper[before] : blockStateMapper[before]; + if (state == before) { + return; + } + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeBlockPos(pos); + buf.writeVarInt(state); + } + } + + public static class LevelParticleListener1_21_4 implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public LevelParticleListener1_21_4(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + boolean overrideLimiter = buf.readBoolean(); + boolean alwaysShow = buf.readBoolean(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + float xDist = buf.readFloat(); + float yDist = buf.readFloat(); + float zDist = buf.readFloat(); + float maxSpeed = buf.readFloat(); + int count = buf.readInt(); + Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); + if (option == null) return; + if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; + Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); + int id = BlockStateUtils.blockStateToId(blockState); + int remapped = user.clientModEnabled() ? modBlockStateMapper[id] : blockStateMapper[id]; + if (remapped == id) return; + Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); + Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeBoolean(overrideLimiter); + buf.writeBoolean(alwaysShow); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeFloat(xDist); + buf.writeFloat(yDist); + buf.writeFloat(zDist); + buf.writeFloat(maxSpeed); + buf.writeInt(count); + FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); + } + } + + public static class LevelParticleListener1_20_5 implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public LevelParticleListener1_20_5(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + boolean overrideLimiter = buf.readBoolean(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + float xDist = buf.readFloat(); + float yDist = buf.readFloat(); + float zDist = buf.readFloat(); + float maxSpeed = buf.readFloat(); + int count = buf.readInt(); + Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); + if (option == null) return; + if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; + Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); + int id = BlockStateUtils.blockStateToId(blockState); + int remapped = user.clientModEnabled() ? modBlockStateMapper[id] : blockStateMapper[id]; + if (remapped == id) return; + Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); + Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeBoolean(overrideLimiter); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeFloat(xDist); + buf.writeFloat(yDist); + buf.writeFloat(zDist); + buf.writeFloat(maxSpeed); + buf.writeInt(count); + FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); + } + } + + public static class LevelParticleListener1_20 implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public LevelParticleListener1_20(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + Object particleType = FastNMS.INSTANCE.method$FriendlyByteBuf$readById(buf, MBuiltInRegistries.PARTICLE_TYPE); + boolean overrideLimiter = buf.readBoolean(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + float xDist = buf.readFloat(); + float yDist = buf.readFloat(); + float zDist = buf.readFloat(); + float maxSpeed = buf.readFloat(); + int count = buf.readInt(); + Object option = FastNMS.INSTANCE.method$ClientboundLevelParticlesPacket$readParticle(buf, particleType); + if (option == null) return; + if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; + Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); + int id = BlockStateUtils.blockStateToId(blockState); + int remapped = user.clientModEnabled() ? modBlockStateMapper[id] : blockStateMapper[id]; + if (remapped == id) return; + Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); + Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeId(buf, remappedOption, MBuiltInRegistries.PARTICLE_TYPE); + buf.writeBoolean(overrideLimiter); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeFloat(xDist); + buf.writeFloat(yDist); + buf.writeFloat(zDist); + buf.writeFloat(maxSpeed); + buf.writeInt(count); + FastNMS.INSTANCE.method$ParticleOptions$writeToNetwork(remappedOption, buf); + } + } + + public static class LevelEventListener implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public LevelEventListener(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int eventId = buf.readInt(); + if (eventId != WorldEvents.BLOCK_BREAK_EFFECT) return; + BlockPos blockPos = buf.readBlockPos(); + int state = buf.readInt(); + boolean global = buf.readBoolean(); + int newState = user.clientModEnabled() ? modBlockStateMapper[state] : blockStateMapper[state]; + Object blockState = BlockStateUtils.idToBlockState(newState); + Object block = BlockStateUtils.getBlockOwner(blockState); + if (BukkitBlockManager.instance().isBlockSoundRemoved(block) && !FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) { + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); + Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString()); + Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId); + if (mappedSoundId != null) { + Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty()); + Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); + Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( + mappedBreakSoundHolder, + CoreReflections.instance$SoundSource$BLOCKS, + blockPos.x() + 0.5, + blockPos.y() + 0.5, + blockPos.z() + 0.5, + (FastNMS.INSTANCE.field$SoundType$volume(soundType) + 1.0F) / 2.0F, + FastNMS.INSTANCE.field$SoundType$pitch(soundType) * 0.8F, + RandomUtils.generateRandomLong() + ); + user.sendPacket(packet, true); + } + } + if (newState == state) { + return; + } + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeInt(eventId); + buf.writeBlockPos(blockPos); + buf.writeInt(newState); + buf.writeBoolean(global); + } + } + + public static class OpenScreenListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptContainer()) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readVarInt(); + int type = buf.readVarInt(); + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(containerId); + buf.writeVarInt(type); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + + public static class OpenScreenListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptContainer()) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readVarInt(); + int type = buf.readVarInt(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(containerId); + buf.writeVarInt(type); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + + public static class SystemChatListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptSystemChat()) return; + FriendlyByteBuf buf = event.getBuffer(); + String jsonOrPlainString = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(jsonOrPlainString); + if (tokens.isEmpty()) return; + boolean overlay = buf.readBoolean(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(jsonOrPlainString), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + buf.writeBoolean(overlay); + } + } + + public static class SystemChatListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptSystemChat()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + boolean overlay = buf.readBoolean(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeBoolean(overlay); + } + } + + public static class TabListListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTabList()) return; + FriendlyByteBuf buf = event.getBuffer(); + String json1 = buf.readUtf(); + String json2 = buf.readUtf(); + Map tokens1 = CraftEngine.instance().fontManager().matchTags(json1); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(json2); + if (tokens1.isEmpty() && tokens2.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); + buf.writeUtf(tokens1.isEmpty() ? json1 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json1), tokens1, context))); + buf.writeUtf(tokens2.isEmpty() ? json2 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json2), tokens2, context))); + } + } + + public static class TabListListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTabList()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt1 = buf.readNbt(false); + if (nbt1 == null) return; + Tag nbt2 = buf.readNbt(false); + if (nbt2 == null) return; + Map tokens1 = CraftEngine.instance().fontManager().matchTags(nbt1.getAsString()); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(nbt2.getAsString()); + if (tokens1.isEmpty() && tokens2.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); + buf.writeNbt(tokens1.isEmpty() ? nbt1 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt1), tokens1, context)), false); + buf.writeNbt(tokens2.isEmpty() ? nbt2 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt2), tokens2, context)), false); + } + } + + public static class SetActionBarListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptActionBar()) return; + FriendlyByteBuf buf = event.getBuffer(); + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + + public static class SetActionBarListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptActionBar()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + + public static class SetTitleListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTitle()) return; + FriendlyByteBuf buf = event.getBuffer(); + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + + public static class SetTitleListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTitle()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + + public static class SetSubtitleListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTitle()) return; + FriendlyByteBuf buf = event.getBuffer(); + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + + public static class SetSubtitleListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTitle()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + + public static class BossEventListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptBossBar()) return; + FriendlyByteBuf buf = event.getBuffer(); + UUID uuid = buf.readUUID(); + int actionType = buf.readVarInt(); + if (actionType == 0) { + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + float health = buf.readFloat(); + int color = buf.readVarInt(); + int division = buf.readVarInt(); + byte flag = buf.readByte(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUUID(uuid); + buf.writeVarInt(actionType); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + buf.writeFloat(health); + buf.writeVarInt(color); + buf.writeVarInt(division); + buf.writeByte(flag); + } else if (actionType == 3) { + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUUID(uuid); + buf.writeVarInt(actionType); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + } + + public static class BossEventListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptBossBar()) return; + FriendlyByteBuf buf = event.getBuffer(); + UUID uuid = buf.readUUID(); + int actionType = buf.readVarInt(); + if (actionType == 0) { + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + float health = buf.readFloat(); + int color = buf.readVarInt(); + int division = buf.readVarInt(); + byte flag = buf.readByte(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUUID(uuid); + buf.writeVarInt(actionType); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeFloat(health); + buf.writeVarInt(color); + buf.writeVarInt(division); + buf.writeByte(flag); + } else if (actionType == 3) { + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUUID(uuid); + buf.writeVarInt(actionType); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + } + + public static class TeamListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTeam()) return; + FriendlyByteBuf buf = event.getBuffer(); + String name = buf.readUtf(); + byte method = buf.readByte(); + if (method != 2 && method != 0) + return; + String displayName = buf.readUtf(); + byte friendlyFlags = buf.readByte(); + String nameTagVisibility = buf.readUtf(40); + String collisionRule = buf.readUtf(40); + int color = buf.readVarInt(); + String prefix = buf.readUtf(); + String suffix = buf.readUtf(); + + Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(prefix); + Map tokens3 = CraftEngine.instance().fontManager().matchTags(suffix); + if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; + event.setChanged(true); + NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); + + List entities = method == 0 ? buf.readStringList() : null; + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(name); + buf.writeByte(method); + buf.writeUtf(tokens1.isEmpty() ? displayName : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens1, context))); + buf.writeByte(friendlyFlags); + buf.writeUtf(nameTagVisibility); + buf.writeUtf(collisionRule); + buf.writeVarInt(color); + buf.writeUtf(tokens2.isEmpty() ? prefix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(prefix), tokens2, context))); + buf.writeUtf(tokens3.isEmpty() ? suffix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(suffix), tokens3, context))); + if (entities != null) { + buf.writeStringList(entities); + } + } + } + + public static class TeamListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTeam()) return; + FriendlyByteBuf buf = event.getBuffer(); + String name = buf.readUtf(); + byte method = buf.readByte(); + if (method != 2 && method != 0) return; + Tag displayName = buf.readNbt(false); + if (displayName == null) return; + byte friendlyFlags = buf.readByte(); + Either eitherVisibility = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); + Either eitherCollisionRule = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); + int color = buf.readVarInt(); + Tag prefix = buf.readNbt(false); + if (prefix == null) return; + Tag suffix = buf.readNbt(false); + if (suffix == null) return; + Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(prefix.getAsString()); + Map tokens3 = CraftEngine.instance().fontManager().matchTags(suffix.getAsString()); + if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; + NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); + List entities = method == 0 ? buf.readStringList() : null; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(name); + buf.writeByte(method); + buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1, context)), false); + buf.writeByte(friendlyFlags); + eitherVisibility.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); + eitherCollisionRule.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); + buf.writeVarInt(color); + buf.writeNbt(tokens2.isEmpty() ? prefix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(prefix), tokens2, context)), false); + buf.writeNbt(tokens3.isEmpty() ? suffix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(suffix), tokens3, context)), false); + if (entities != null) { + buf.writeStringList(entities); + } + } + } + + public static class SetObjectiveListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptScoreboard()) return; + FriendlyByteBuf buf = event.getBuffer(); + String objective = buf.readUtf(); + byte mode = buf.readByte(); + if (mode != 0 && mode != 2) return; + String displayName = buf.readUtf(); + int renderType = buf.readVarInt(); + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + buf.writeVarInt(renderType); + } + } + + public static class SetObjectiveListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptScoreboard()) return; + FriendlyByteBuf buf = event.getBuffer(); + String objective = buf.readUtf(); + byte mode = buf.readByte(); + if (mode != 0 && mode != 2) return; + Tag displayName = buf.readNbt(false); + if (displayName == null) return; + int renderType = buf.readVarInt(); + boolean optionalNumberFormat = buf.readBoolean(); + if (optionalNumberFormat) { + int format = buf.readVarInt(); + if (format == 0) { + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeVarInt(renderType); + buf.writeBoolean(true); + buf.writeVarInt(0); + } else if (format == 1) { + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + if (tokens.isEmpty()) return; + Tag style = buf.readNbt(false); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeVarInt(renderType); + buf.writeBoolean(true); + buf.writeVarInt(1); + buf.writeNbt(style, false); + } else if (format == 2) { + Tag fixed = buf.readNbt(false); + if (fixed == null) return; + Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(fixed.getAsString()); + if (tokens1.isEmpty() && tokens2.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeVarInt(renderType); + buf.writeBoolean(true); + buf.writeVarInt(2); + buf.writeNbt(tokens2.isEmpty() ? fixed : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(fixed), tokens2, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } else { + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeVarInt(renderType); + buf.writeBoolean(false); + } + } + } + + public static class SetScoreListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptSetScore()) return; + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + boolean isChanged = false; + FriendlyByteBuf buf = event.getBuffer(); + String owner = buf.readUtf(); + String objectiveName = buf.readUtf(); + int score = buf.readVarInt(); + boolean hasDisplay = buf.readBoolean(); + Tag displayName = null; + if (hasDisplay) { + displayName = buf.readNbt(false); + } + outside: + if (displayName != null) { + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + if (tokens.isEmpty()) break outside; + Component component = AdventureHelper.tagToComponent(displayName); + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); + displayName = AdventureHelper.componentToTag(component); + isChanged = true; + } + boolean hasNumberFormat = buf.readBoolean(); + int format = -1; + Tag style = null; + Tag fixed = null; + if (hasNumberFormat) { + format = buf.readVarInt(); + if (format == 0) { + if (displayName == null) return; + } else if (format == 1) { + if (displayName == null) return; + style = buf.readNbt(false); + } else if (format == 2) { + fixed = buf.readNbt(false); + if (fixed == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(fixed.getAsString()); + if (tokens.isEmpty() && !isChanged) return; + if (!tokens.isEmpty()) { + Component component = AdventureHelper.tagToComponent(fixed); + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); + fixed = AdventureHelper.componentToTag(component); + isChanged = true; + } + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(owner); + buf.writeUtf(objectiveName); + buf.writeVarInt(score); + if (hasDisplay) { + buf.writeBoolean(true); + buf.writeNbt(displayName, false); + } else { + buf.writeBoolean(false); + } + if (hasNumberFormat) { + buf.writeBoolean(true); + buf.writeVarInt(format); + if (format == 1) { + buf.writeNbt(style, false); + } else if (format == 2) { + buf.writeNbt(fixed, false); + } + } else { + buf.writeBoolean(false); + } + } + } + } + + public static class AddRecipeBookListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + 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); + } + } + + public static class PlaceGhostRecipeListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + 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); + } + } + + public static class UpdateRecipesListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + 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))); + } + } + + public static class UpdateAdvancementsListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + boolean reset = buf.readBoolean(); + List added = buf.readCollection(ArrayList::new, byteBuf -> { + AdvancementHolder holder = AdvancementHolder.read(byteBuf); + holder.applyClientboundData(serverPlayer); + 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); + } + } + } + + public static class RemoveEntityListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + boolean isChange = false; + IntList intList = buf.readIntIdList(); + for (int i = 0, size = intList.size(); i < size; i++) { + int entityId = intList.getInt(i); + EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); + if (handler != null && handler.handleEntitiesRemove(intList)) { + isChange = true; + } + } + if (isChange) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeIntIdList(intList); + } + } + } + + public static class SoundListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + if (id == 0) { + Key soundId = buf.readKey(); + Float range = null; + if (buf.readBoolean()) { + range = buf.readFloat(); + } + int source = buf.readVarInt(); + int x = buf.readInt(); + int y = buf.readInt(); + int z = buf.readInt(); + float volume = buf.readFloat(); + float pitch = buf.readFloat(); + long seed = buf.readLong(); + Key mapped = BukkitBlockManager.instance().replaceSoundIfExist(soundId); + if (mapped != null) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(0); + buf.writeKey(mapped); + if (range != null) { + buf.writeBoolean(true); + buf.writeFloat(range); + } else { + buf.writeBoolean(false); + } + buf.writeVarInt(source); + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + buf.writeFloat(volume); + buf.writeFloat(pitch); + buf.writeLong(seed); + } + } else { + Optional optionalSound = FastNMS.INSTANCE.method$IdMap$byId(MBuiltInRegistries.SOUND_EVENT, id - 1); + if (optionalSound.isEmpty()) return; + Object soundEvent = optionalSound.get(); + Key soundId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$SoundEvent$location(soundEvent)); + int source = buf.readVarInt(); + int x = buf.readInt(); + int y = buf.readInt(); + int z = buf.readInt(); + float volume = buf.readFloat(); + float pitch = buf.readFloat(); + long seed = buf.readLong(); + Key mapped = BukkitBlockManager.instance().replaceSoundIfExist(soundId); + if (mapped != null) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(0); + Object newId = KeyUtils.toResourceLocation(mapped); + Object newSoundEvent = FastNMS.INSTANCE.constructor$SoundEvent(newId, FastNMS.INSTANCE.method$SoundEvent$fixedRange(soundEvent)); + FastNMS.INSTANCE.method$SoundEvent$directEncode(buf, newSoundEvent); + buf.writeVarInt(source); + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + buf.writeFloat(volume); + buf.writeFloat(pitch); + buf.writeLong(seed); + } + } + } + } + + public static class ContainerSetContentListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + int listSize = buf.readVarInt(); + List items = new ArrayList<>(listSize); + boolean changed = false; + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for (int i = 0; i < listSize; i++) { + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); + if (optional.isPresent()) { + items.add(optional.get()); + changed = true; + } else { + items.add(itemStack); + } + } + ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + ItemStack newCarriedItem = carriedItem; + Optional optional = BukkitItemManager.instance().s2c(carriedItem, serverPlayer); + if (optional.isPresent()) { + changed = true; + newCarriedItem = optional.get(); + } + if (!changed) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeVarInt(listSize); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for (ItemStack itemStack : items) { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); + } + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newCarriedItem); + } + } + + public static class ContainerSetSlotListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + int slot = buf.readShort(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + 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(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeShort(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } + } + + public static class SetCursorItemListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } + } + + public static class SetEquipmentListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + boolean changed = false; + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + int entity = buf.readVarInt(); + List> slots = Lists.newArrayList(); + int slotMask; + do { + slotMask = buf.readByte(); + Object equipmentSlot = CoreReflections.instance$EquipmentSlot$values[slotMask & 127]; + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); + if (optional.isPresent()) { + changed = true; + itemStack = optional.get(); + } + slots.add(com.mojang.datafixers.util.Pair.of(equipmentSlot, itemStack)); + } while ((slotMask & -128) != 0); + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(entity); + int i = slots.size(); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for (int j = 0; j < i; ++j) { + com.mojang.datafixers.util.Pair pair = slots.get(j); + Enum equipmentSlot = (Enum) pair.getFirst(); + boolean bl = j != i - 1; + int k = equipmentSlot.ordinal(); + buf.writeByte(bl ? k | -128 : k); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond()); + } + } + } + } + + public static class SetPlayerInventoryListener1_21_2 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int slot = buf.readVarInt(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } + } + + public static class SetCreativeModeSlotListener implements ByteBufferPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + if (!serverPlayer.isCreativeMode()) return; + FriendlyByteBuf buf = event.getBuffer(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + short slotNum = buf.readShort(); + ItemStack itemStack; + try { + itemStack = VersionHelper.isOrAbove1_20_5() ? + FastNMS.INSTANCE.method$FriendlyByteBuf$readUntrustedItem(friendlyBuf) : FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + } catch (Exception e) { + return; + } + BukkitItemManager.instance().c2s(itemStack).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeShort(slotNum); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + if (VersionHelper.isOrAbove1_20_5()) { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeUntrustedItem(newFriendlyBuf, newItemStack); + } else { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + } + }); + } + } + + public static class ContainerClick1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + boolean changed = false; + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + short slotNum = buf.readShort(); + byte buttonNum = buf.readByte(); + int clickType = buf.readVarInt(); + int i = buf.readVarInt(); + Int2ObjectMap changedSlots = new Int2ObjectOpenHashMap<>(i); + for (int j = 0; j < i; ++j) { + int k = buf.readShort(); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().c2s(itemStack); + if (optional.isPresent()) { + changed = true; + itemStack = optional.get(); + } + changedSlots.put(k, itemStack); + } + ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().c2s(carriedItem); + if (optional.isPresent()) { + changed = true; + carriedItem = optional.get(); + } + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeShort(slotNum); + buf.writeByte(buttonNum); + buf.writeVarInt(clickType); + buf.writeVarInt(changedSlots.size()); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + changedSlots.forEach((k, v) -> { + buf.writeShort(k); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, v); + }); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, carriedItem); + } + } + } + + public class InteractEntityListener implements ByteBufferPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int entityId = hasModelEngine() ? plugin.compatibilityManager().interactionToBaseEntity(buf.readVarInt()) : buf.readVarInt(); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); + if (furniture == null) return; + int actionType = buf.readVarInt(); + BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; + if (serverPlayer.isSpectatorMode()) return; + Player platformPlayer = serverPlayer.platformPlayer(); + Location location = furniture.baseEntity().getLocation(); + + Runnable mainThreadTask; + if (actionType == 1) { + // ATTACK + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeBoolean(usingSecondaryAction); + } + + mainThreadTask = () -> { + // todo 冒险模式破坏工具白名单 + if (serverPlayer.isAdventureMode() || + !furniture.isValid()) return; + + // todo 重构家具时候注意,需要准备加载好的hitbox类,以获取hitbox坐标 + if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { + return; + } + + FurnitureAttemptBreakEvent preBreakEvent = new FurnitureAttemptBreakEvent(serverPlayer.platformPlayer(), furniture); + if (EventUtils.fireAndCheckCancel(preBreakEvent)) + return; + + if (!BukkitCraftEngine.instance().antiGriefProvider().canBreak(platformPlayer, location)) + return; + + FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture); + if (EventUtils.fireAndCheckCancel(breakEvent)) + return; + + Cancellable cancellable = Cancellable.of(breakEvent::isCancelled, breakEvent::setCancelled); + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.HAND, InteractionHand.MAIN_HAND) + .withParameter(DirectContextParameters.ITEM_IN_HAND, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)) + .withParameter(DirectContextParameters.POSITION, furniture.position()) + ); + furniture.config().execute(context, EventTrigger.LEFT_CLICK); + furniture.config().execute(context, EventTrigger.BREAK); + if (cancellable.isCancelled()) { + return; + } + + CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); + }; + } else if (actionType == 2) { + // INTERACT_AT + float x = buf.readFloat(); + float y = buf.readFloat(); + float z = buf.readFloat(); + // todo 这个是错误的,这是实体的相对位置而非绝对位置 + Location interactionPoint = new Location(platformPlayer.getWorld(), x, y, z); + InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeFloat(x).writeFloat(y).writeFloat(z); + buf.writeVarInt(hand == InteractionHand.MAIN_HAND ? 0 : 1); + buf.writeBoolean(usingSecondaryAction); + } + + mainThreadTask = () -> { + if (!furniture.isValid()) { + return; + } + + // todo 重构家具时候注意,需要准备加载好的hitbox类,以获取hitbox坐标 + if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { + return; + } + + FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint); + if (EventUtils.fireAndCheckCancel(interactEvent)) { + return; + } + + Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); + Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled); + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.POSITION, furniture.position()) + ); + furniture.config().execute(context, EventTrigger.RIGHT_CLICK); + if (cancellable.isCancelled()) { + return; + } + + // 必须从网络包层面处理,否则无法获取交互的具体实体 + if (serverPlayer.isSecondaryUseActive() && !itemInHand.isEmpty()) { + // try placing another furniture above it + AABB hitBox = furniture.aabbByEntityId(entityId); + if (hitBox == null) return; + Optional> optionalCustomItem = itemInHand.getCustomItem(); + Location eyeLocation = platformPlayer.getEyeLocation(); + Vector direction = eyeLocation.getDirection(); + Location endLocation = eyeLocation.clone(); + endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); + Optional result = hitBox.clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation)); + if (result.isEmpty()) { + return; + } + EntityHitResult hitResult = result.get(); + if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) { + for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) { + if (behavior instanceof FurnitureItemBehavior) { + behavior.useOnBlock(new UseOnContext(serverPlayer, InteractionHand.MAIN_HAND, new BlockHitResult(hitResult.hitLocation(), hitResult.direction(), BlockPos.fromVec3d(hitResult.hitLocation()), false))); + return; + } + } + } + // now simulate vanilla item behavior + serverPlayer.setResendSound(); + FastNMS.INSTANCE.simulateInteraction( + serverPlayer.serverPlayer(), + DirectionUtils.toNMSDirection(hitResult.direction()), + hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z, + LocationUtils.toBlockPos(hitResult.blockPos()) + ); + } else { + if (!serverPlayer.isSecondaryUseActive()) { + furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { + if (furniture.tryOccupySeat(seatPos)) { + furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos); + } + }); + } + } + }; + } else if (actionType == 0) { + int hand = buf.readVarInt(); + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeVarInt(hand); + buf.writeBoolean(usingSecondaryAction); + } + return; + } else { + return; + } + + if (VersionHelper.isFolia()) { + platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), t -> mainThreadTask.run(), () -> {}); + } else { + BukkitCraftEngine.instance().scheduler().executeSync(mainThreadTask); + } + } + } + + public static class CustomPayloadListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + if (VersionHelper.isOrAbove1_20_2()) return; + FriendlyByteBuf byteBuf = event.getBuffer(); + Key key = byteBuf.readKey(); + if (!key.equals(NetworkManager.MOD_CHANNEL_KEY)) return; + PayloadHelper.handleReceiver(new UnknownPayload(key, byteBuf.readBytes(byteBuf.readableBytes())), user); + } + } + + public class AddEntityListener implements ByteBufferPacketListener { + private final EntityTypeHandler[] handlers; + + public AddEntityListener(int entityTypes) { + this.handlers = new EntityTypeHandler[entityTypes]; + Arrays.fill(this.handlers, EntityTypeHandler.DoNothing.INSTANCE); + this.handlers[MEntityTypes.BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE); + this.handlers[MEntityTypes.TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE); + this.handlers[MEntityTypes.ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE); + this.handlers[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + this.handlers[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); + this.handlers[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); + this.handlers[MEntityTypes.ENDERMAN$registryId] = simpleAddEntityHandler(EndermanPacketHandler.INSTANCE); + this.handlers[MEntityTypes.CHEST_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.COMMAND_BLOCK_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.FURNACE_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.HOPPER_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.SPAWNER_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.TNT_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.EGG$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.POTION$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler(false); + this.handlers[MEntityTypes.ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); + this.handlers[MEntityTypes.SPECTRAL_ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); + if (VersionHelper.isOrAbove1_20_3()) { + this.handlers[MEntityTypes.TNT$registryId] = simpleAddEntityHandler(PrimedTNTPacketHandler.INSTANCE); + } + if (VersionHelper.isOrAbove1_20_5()) { + this.handlers[MEntityTypes.OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + } + this.handlers[MEntityTypes.FALLING_BLOCK$registryId] = (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + UUID uuid = buf.readUUID(); + int type = buf.readVarInt(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + byte xRot = buf.readByte(); + byte yRot = buf.readByte(); + byte yHeadRot = buf.readByte(); + int data = buf.readVarInt(); + // Falling blocks + int remapped = remapBlockState(data, user.clientModEnabled()); + if (remapped != data) { + int xa = buf.readShort(); + int ya = buf.readShort(); + int za = buf.readShort(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + buf.writeUUID(uuid); + buf.writeVarInt(type); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeByte(xRot); + buf.writeByte(yRot); + buf.writeByte(yHeadRot); + buf.writeVarInt(remapped); + buf.writeShort(xa); + buf.writeShort(ya); + buf.writeShort(za); + } }; + this.handlers[MEntityTypes.ITEM_DISPLAY$registryId] = (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); + if (furniture != null) { + user.entityPacketHandlers().put(id, new FurniturePacketHandler(furniture.fakeEntityIds())); + user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); + if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { + event.setCancelled(true); + } + } else { + user.entityPacketHandlers().put(id, ItemDisplayPacketHandler.INSTANCE); + } + }; + this.handlers[MEntityTypes.INTERACTION$registryId] = (user, event) -> { + if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.INTERACTION) return; + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + // Cancel collider entity packet + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); + if (furniture != null) { + event.setCancelled(true); + user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); + } + }; + this.handlers[MEntityTypes.OAK_BOAT$registryId] = (user, event) -> { + if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.OAK_BOAT) return; + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + // Cancel collider entity packet + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); + if (furniture != null) { + event.setCancelled(true); + user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); + } + }; + } + + private static EntityTypeHandler simpleAddEntityHandler(EntityPacketHandler handler) { + return (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + user.entityPacketHandlers().put(buf.readVarInt(), handler); + }; + } + + private static EntityTypeHandler createOptionalCustomProjectileEntityHandler(boolean fallback) { + return (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + BukkitProjectileManager.instance().projectileByEntityId(id).ifPresentOrElse(customProjectile -> { + ProjectilePacketHandler handler = new ProjectilePacketHandler(customProjectile, id); + handler.convertAddCustomProjectilePacket(buf, event); + user.entityPacketHandlers().put(id, handler); + }, () -> { + if (fallback) { + user.entityPacketHandlers().put(id, CommonItemPacketHandler.INSTANCE); + } + }); + }; + } + + public interface EntityTypeHandler { + + void handle(NetWorkUser user, ByteBufPacketEvent event); + + class DoNothing implements EntityTypeHandler { + public static final DoNothing INSTANCE = new DoNothing(); + + @Override + public void handle(NetWorkUser user, ByteBufPacketEvent event) { + } + } + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + buf.readVarInt(); + buf.readUUID(); + int type = buf.readVarInt(); + this.handlers[type].handle(user, event); + } + } + + public static class SetEntityDataListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + EntityPacketHandler handler = user.entityPacketHandlers().get(id); + if (handler != null) { + handler.handleSetEntityData(serverPlayer, event); + return; + } + if (Config.interceptEntityName()) { + 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 != BaseEntityData.CustomName.id()) continue; + // noinspection 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); + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); + 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); + 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/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java deleted file mode 100644 index 9a1c5bafa..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ /dev/null @@ -1,2703 +0,0 @@ -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; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntList; -import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; -import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; -import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent; -import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; -import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; -import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; -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.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor; -import net.momirealms.craftengine.bukkit.plugin.network.handler.*; -import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; -import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; -import net.momirealms.craftengine.bukkit.plugin.network.payload.PayloadHelper; -import net.momirealms.craftengine.bukkit.plugin.network.payload.UnknownPayload; -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.MEntityTypes; -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.bukkit.world.BukkitWorldManager; -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; -import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; -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; -import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext; -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.locale.TranslationManager; -import net.momirealms.craftengine.core.plugin.logger.Debugger; -import net.momirealms.craftengine.core.plugin.network.*; -import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; -import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.world.*; -import net.momirealms.craftengine.core.world.chunk.CEChunk; -import net.momirealms.craftengine.core.world.chunk.ChunkStatus; -import net.momirealms.craftengine.core.world.chunk.Palette; -import net.momirealms.craftengine.core.world.chunk.PalettedContainer; -import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; -import net.momirealms.craftengine.core.world.chunk.packet.MCSection; -import net.momirealms.craftengine.core.world.collision.AABB; -import net.momirealms.sparrow.nbt.Tag; -import org.bukkit.*; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.util.RayTraceResult; -import org.bukkit.util.Vector; -import org.jetbrains.annotations.Nullable; - -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -public class PacketConsumers { - private static BukkitNetworkManager.Handlers[] ADD_ENTITY_HANDLERS; - private static int[] BLOCK_STATE_MAPPINGS; - private static int[] MOD_BLOCK_STATE_MAPPINGS; - private static IntIdentityList SERVER_BLOCK_LIST; - private static IntIdentityList BIOME_LIST; - private static Consumer> BIOME_MAPPER; - - public static void initEntities(int registrySize) { - ADD_ENTITY_HANDLERS = new BukkitNetworkManager.Handlers[registrySize]; - Arrays.fill(ADD_ENTITY_HANDLERS, BukkitNetworkManager.Handlers.DO_NOTHING); - ADD_ENTITY_HANDLERS[MEntityTypes.FALLING_BLOCK$registryId] = (user, event) -> { - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - UUID uuid = buf.readUUID(); - int type = buf.readVarInt(); - double x = buf.readDouble(); - double y = buf.readDouble(); - double z = buf.readDouble(); - byte xRot = buf.readByte(); - byte yRot = buf.readByte(); - byte yHeadRot = buf.readByte(); - int data = buf.readVarInt(); - // Falling blocks - int remapped = user.clientModEnabled() ? remapMOD(data) : remap(data); - if (remapped != data) { - int xa = buf.readShort(); - int ya = buf.readShort(); - int za = buf.readShort(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - buf.writeUUID(uuid); - buf.writeVarInt(type); - buf.writeDouble(x); - buf.writeDouble(y); - buf.writeDouble(z); - buf.writeByte(xRot); - buf.writeByte(yRot); - buf.writeByte(yHeadRot); - buf.writeVarInt(remapped); - buf.writeShort(xa); - buf.writeShort(ya); - buf.writeShort(za); - } - }; - - ADD_ENTITY_HANDLERS[MEntityTypes.BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.ENDERMAN$registryId] = simpleAddEntityHandler(EndermanPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.CHEST_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.COMMAND_BLOCK_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.FURNACE_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.HOPPER_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.SPAWNER_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.TNT_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.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); - ADD_ENTITY_HANDLERS[MEntityTypes.SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.EGG$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.POTION$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler(false); - ADD_ENTITY_HANDLERS[MEntityTypes.ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); - ADD_ENTITY_HANDLERS[MEntityTypes.SPECTRAL_ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); - if (VersionHelper.isOrAbove1_20_3()) { - ADD_ENTITY_HANDLERS[MEntityTypes.TNT$registryId] = simpleAddEntityHandler(PrimedTNTPacketHandler.INSTANCE); - } - if (VersionHelper.isOrAbove1_20_5()) { - ADD_ENTITY_HANDLERS[MEntityTypes.OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); - } - - ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_DISPLAY$registryId] = (user, event) -> { - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); - if (furniture != null) { - user.entityPacketHandlers().put(id, new FurniturePacketHandler(furniture.fakeEntityIds())); - user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); - if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { - event.setCancelled(true); - } - } else { - user.entityPacketHandlers().put(id, ItemDisplayPacketHandler.INSTANCE); - } - }; - ADD_ENTITY_HANDLERS[MEntityTypes.INTERACTION$registryId] = (user, event) -> { - if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.INTERACTION) return; - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - // Cancel collider entity packet - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); - if (furniture != null) { - event.setCancelled(true); - user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); - } - }; - ADD_ENTITY_HANDLERS[MEntityTypes.OAK_BOAT$registryId] = (user, event) -> { - if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.OAK_BOAT) return; - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - // Cancel collider entity packet - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); - if (furniture != null) { - event.setCancelled(true); - user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); - } - }; - } - - private static BukkitNetworkManager.Handlers simpleAddEntityHandler(EntityPacketHandler handler) { - return (user, event) -> { - FriendlyByteBuf buf = event.getBuffer(); - user.entityPacketHandlers().put(buf.readVarInt(), handler); - }; - } - - private static BukkitNetworkManager.Handlers createOptionalCustomProjectileEntityHandler(boolean fallback) { - return (user, event) -> { - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - BukkitProjectileManager.instance().projectileByEntityId(id).ifPresentOrElse(customProjectile -> { - ProjectilePacketHandler handler = new ProjectilePacketHandler(customProjectile, id); - handler.convertAddCustomProjectilePacket(buf, event); - user.entityPacketHandlers().put(id, handler); - }, () -> { - if (fallback) { - user.entityPacketHandlers().put(id, CommonItemPacketHandler.INSTANCE); - } - }); - }; - } - - public static void setBiomeMapper(Consumer> mapper) { - BIOME_MAPPER = mapper; - } - - public static void remapBiomes(PalettedContainer biomes) { - if (BIOME_MAPPER != null) { - BIOME_MAPPER.accept(biomes); - } - } - - public static void initBlocks(Map map, int registrySize) { - int[] newMappings = new int[registrySize]; - for (int i = 0; i < registrySize; i++) { - newMappings[i] = i; - } - int[] newMappingsMOD = Arrays.copyOf(newMappings, registrySize); - for (Map.Entry entry : map.entrySet()) { - newMappings[entry.getKey()] = entry.getValue(); - if (BlockStateUtils.isVanillaBlock((int) entry.getKey())) { - newMappingsMOD[entry.getKey()] = entry.getValue(); - } - } - for (int i = 0; i < newMappingsMOD.length; i++) { - if (BlockStateUtils.isVanillaBlock(i)) { - newMappingsMOD[i] = newMappings[i]; - } - } - BLOCK_STATE_MAPPINGS = newMappings; - MOD_BLOCK_STATE_MAPPINGS = newMappingsMOD; - SERVER_BLOCK_LIST = new IntIdentityList(registrySize); - BIOME_LIST = new IntIdentityList(RegistryUtils.currentBiomeRegistrySize()); - } - - public static int remap(int stateId) { - return BLOCK_STATE_MAPPINGS[stateId]; - } - - public static int remapMOD(int stateId) { - return MOD_BLOCK_STATE_MAPPINGS[stateId]; - } - - public static final BiConsumer FORGET_LEVEL_CHUNK = (user, event) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - FriendlyByteBuf buf = event.getBuffer(); - CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid()); - if (VersionHelper.isOrAbove1_20_2()) { - long chunkPos = buf.readLong(); - user.removeTrackedChunk(chunkPos); - CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos); - if (ceChunk != null) { - ceChunk.despawnBlockEntities(player); - } - } else { - int x = buf.readInt(); - int y = buf.readInt(); - user.removeTrackedChunk(ChunkPos.asLong(x, y)); - CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(x, y); - if (ceChunk != null) { - ceChunk.despawnBlockEntities(player); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundForgetLevelChunkPacket", e); - } - }; - - public static final BiConsumer LEVEL_CHUNK_WITH_LIGHT = (user, event) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - FriendlyByteBuf buf = event.getBuffer(); - int chunkX = buf.readInt(); - int chunkZ = buf.readInt(); - boolean named = !VersionHelper.isOrAbove1_20_2(); - // ClientboundLevelChunkPacketData - int heightmapsCount = 0; - Map heightmapsMap = null; - Tag heightmaps = null; - if (VersionHelper.isOrAbove1_21_5()) { - heightmapsMap = new HashMap<>(); - heightmapsCount = buf.readVarInt(); - for (int i = 0; i < heightmapsCount; i++) { - int key = buf.readVarInt(); - long[] value = buf.readLongArray(); - heightmapsMap.put(key, value); - } - } else { - heightmaps = buf.readNbt(named); - } - - int varInt = buf.readVarInt(); - byte[] buffer = new byte[varInt]; - buf.readBytes(buffer); - int blockEntitiesDataCount = buf.readVarInt(); - List blockEntitiesData = new ArrayList<>(); - for (int i = 0; i < blockEntitiesDataCount; i++) { - byte packedXZ = buf.readByte(); - short y = buf.readShort(); - int type = buf.readVarInt(); - Tag tag = buf.readNbt(named); - BlockEntityData blockEntityData = new BlockEntityData(packedXZ, y, type, tag); - blockEntitiesData.add(blockEntityData); - } - // ClientboundLightUpdatePacketData - BitSet skyYMask = buf.readBitSet(); - BitSet blockYMask = buf.readBitSet(); - BitSet emptySkyYMask = buf.readBitSet(); - BitSet emptyBlockYMask = buf.readBitSet(); - List skyUpdates = buf.readByteArrayList(2048); - List blockUpdates = buf.readByteArrayList(2048); - // 开始处理 - if (user.clientModEnabled()) { - ByteBuf byteBuf = Unpooled.copiedBuffer(buffer); - FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); - FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); - for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { - MCSection mcSection = new MCSection(user.clientBlockList(), SERVER_BLOCK_LIST, BIOME_LIST); - mcSection.readPacket(friendlyByteBuf); - PalettedContainer container = mcSection.blockStateContainer(); - remapBiomes(mcSection.biomeContainer()); - Palette palette = container.data().palette(); - if (palette.canRemap()) { - palette.remap(PacketConsumers::remapMOD); - } else { - for (int j = 0; j < 4096; j++) { - int state = container.get(j); - int newState = remapMOD(state); - if (newState != state) { - container.set(j, newState); - } - } - } - mcSection.writePacket(newBuf); - } - buffer = newBuf.array(); - } else { - ByteBuf byteBuf = Unpooled.copiedBuffer(buffer); - FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); - FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); - for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { - MCSection mcSection = new MCSection(user.clientBlockList(), SERVER_BLOCK_LIST, BIOME_LIST); - mcSection.readPacket(friendlyByteBuf); - PalettedContainer container = mcSection.blockStateContainer(); - remapBiomes(mcSection.biomeContainer()); - Palette palette = container.data().palette(); - if (palette.canRemap()) { - palette.remap(PacketConsumers::remap); - } else { - for (int j = 0; j < 4096; j++) { - int state = container.get(j); - int newState = remap(state); - if (newState != state) { - container.set(j, newState); - } - } - } - mcSection.writePacket(newBuf); - } - buffer = newBuf.array(); - } - - // 开始修改 - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeInt(chunkX); - buf.writeInt(chunkZ); - if (VersionHelper.isOrAbove1_21_5()) { - buf.writeVarInt(heightmapsCount); - for (Map.Entry entry : heightmapsMap.entrySet()) { - buf.writeVarInt(entry.getKey()); - buf.writeLongArray(entry.getValue()); - } - } else { - buf.writeNbt(heightmaps, named); - } - buf.writeVarInt(buffer.length); - buf.writeBytes(buffer); - buf.writeVarInt(blockEntitiesDataCount); - for (BlockEntityData blockEntityData : blockEntitiesData) { - buf.writeByte(blockEntityData.packedXZ()); - buf.writeShort(blockEntityData.y()); - buf.writeVarInt(blockEntityData.type()); - buf.writeNbt(blockEntityData.tag(), named); - } - buf.writeBitSet(skyYMask); - buf.writeBitSet(blockYMask); - buf.writeBitSet(emptySkyYMask); - buf.writeBitSet(emptyBlockYMask); - buf.writeByteArrayList(skyUpdates); - buf.writeByteArrayList(blockUpdates); - - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - // 记录加载的区块 - player.addTrackedChunk(chunkPos.longKey, new ChunkStatus()); - - CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid()); - CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos.longKey); - if (ceChunk != null) { - ceChunk.spawnBlockEntities(player); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelChunkWithLightPacket", e); - } - }; - - public static final BiConsumer SECTION_BLOCK_UPDATE = (user, event) -> { - try { - if (user.clientModEnabled()) { - FriendlyByteBuf buf = event.getBuffer(); - long pos = buf.readLong(); - int blocks = buf.readVarInt(); - short[] positions = new short[blocks]; - int[] states = new int[blocks]; - for (int i = 0; i < blocks; i++) { - long k = buf.readVarLong(); - positions[i] = (short) ((int) (k & 4095L)); - states[i] = remapMOD((int) (k >>> 12)); - } - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeLong(pos); - buf.writeVarInt(blocks); - for (int i = 0; i < blocks; i++) { - buf.writeVarLong((long) states[i] << 12 | positions[i]); - } - event.setChanged(true); - } else { - FriendlyByteBuf buf = event.getBuffer(); - long pos = buf.readLong(); - int blocks = buf.readVarInt(); - short[] positions = new short[blocks]; - int[] states = new int[blocks]; - for (int i = 0; i < blocks; i++) { - long k = buf.readVarLong(); - positions[i] = (short) ((int) (k & 4095L)); - states[i] = remap((int) (k >>> 12)); - } - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeLong(pos); - buf.writeVarInt(blocks); - for (int i = 0; i < blocks; i++) { - buf.writeVarLong((long) states[i] << 12 | positions[i]); - } - event.setChanged(true); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSectionBlocksUpdatePacket", e); - } - }; - - public static final BiConsumer BLOCK_UPDATE = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - BlockPos pos = buf.readBlockPos(); - int before = buf.readVarInt(); - if (user.clientModEnabled() && !BlockStateUtils.isVanillaBlock(before)) { - return; - } - int state = user.clientModEnabled() ? remapMOD(before) : remap(before); - if (state == before) { - return; - } - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeBlockPos(pos); - buf.writeVarInt(state); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundBlockUpdatePacket", e); - } - }; - - public static final BiConsumer LEVEL_EVENT = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - int eventId = buf.readInt(); - if (eventId != WorldEvents.BLOCK_BREAK_EFFECT) return; - BlockPos blockPos = buf.readBlockPos(); - int state = buf.readInt(); - boolean global = buf.readBoolean(); - int newState = user.clientModEnabled() ? remapMOD(state) : remap(state); - Object blockState = BlockStateUtils.idToBlockState(newState); - Object block = BlockStateUtils.getBlockOwner(blockState); - if (BukkitBlockManager.instance().isBlockSoundRemoved(block) && !FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) { - Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); - Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); - Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString()); - Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId); - if (mappedSoundId != null) { - Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty()); - Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); - Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( - mappedBreakSoundHolder, - CoreReflections.instance$SoundSource$BLOCKS, - blockPos.x() + 0.5, - blockPos.y() + 0.5, - blockPos.z() + 0.5, - (FastNMS.INSTANCE.field$SoundType$volume(soundType) + 1.0F) / 2.0F, - FastNMS.INSTANCE.field$SoundType$pitch(soundType) * 0.8F, - RandomUtils.generateRandomLong() - ); - user.sendPacket(packet, true); - } - } - if (newState == state) { - return; - } - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeInt(eventId); - buf.writeBlockPos(blockPos); - buf.writeInt(newState); - buf.writeBoolean(global); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelEventPacket", e); - } - }; - - public static final BiConsumer TEAM_1_20_3 = (user, event) -> { - if (!Config.interceptTeam()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String name = buf.readUtf(); - byte method = buf.readByte(); - if (method != 2 && method != 0) return; - Tag displayName = buf.readNbt(false); - if (displayName == null) return; - byte friendlyFlags = buf.readByte(); - Either eitherVisibility = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); - Either eitherCollisionRule = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); - int color = buf.readVarInt(); - Tag prefix = buf.readNbt(false); - if (prefix == null) return; - Tag suffix = buf.readNbt(false); - if (suffix == null) return; - Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(prefix.getAsString()); - Map tokens3 = CraftEngine.instance().fontManager().matchTags(suffix.getAsString()); - if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; - NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); - List entities = method == 0 ? buf.readStringList() : null; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(name); - buf.writeByte(method); - buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1, context)), false); - buf.writeByte(friendlyFlags); - eitherVisibility.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); - eitherCollisionRule.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); - buf.writeVarInt(color); - buf.writeNbt(tokens2.isEmpty() ? prefix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(prefix), tokens2, context)), false); - buf.writeNbt(tokens3.isEmpty() ? suffix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(suffix), tokens3, context)), false); - if (entities != null) { - buf.writeStringList(entities); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetPlayerTeamPacket", e); - } - }; - - public static final TriConsumer PLAYER_INFO_UPDATE = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - if (!Config.interceptPlayerInfo()) return; - List entries = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$entries(packet); - if (entries instanceof MarkedArrayList) { - return; - } - EnumSet> enums = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$actions(packet); - outer: { - for (Object entry : enums) { - if (entry == NetworkReflections.instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME) { - break outer; - } - } - return; - } - boolean isChanged = false; - List newEntries = new MarkedArrayList<>(); - for (Object entry : entries) { - Object mcComponent = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$Entry$displayName(entry); - if (mcComponent == null) { - newEntries.add(entry); - } else { - String json = ComponentUtils.minecraftToJson(mcComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) { - newEntries.add(entry); - } else { - Object newEntry = FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket$Entry(entry, - ComponentUtils.adventureToMinecraft(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - newEntries.add(newEntry); - isChanged = true; - } - } - } - if (isChanged) { - event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket(enums, newEntries)); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundPlayerInfoUpdatePacket", e); - } - }; - - public static final BiConsumer TEAM_1_20 = (user, event) -> { - if (!Config.interceptTeam()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String name = buf.readUtf(); - byte method = buf.readByte(); - if (method != 2 && method != 0) - return; - String displayName = buf.readUtf(); - byte friendlyFlags = buf.readByte(); - String nameTagVisibility = buf.readUtf(40); - String collisionRule = buf.readUtf(40); - int color = buf.readVarInt(); - String prefix = buf.readUtf(); - String suffix = buf.readUtf(); - - Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(prefix); - Map tokens3 = CraftEngine.instance().fontManager().matchTags(suffix); - if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; - event.setChanged(true); - NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); - - List entities = method == 0 ? buf.readStringList() : null; - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(name); - buf.writeByte(method); - buf.writeUtf(tokens1.isEmpty() ? displayName : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens1, context))); - buf.writeByte(friendlyFlags); - buf.writeUtf(nameTagVisibility); - buf.writeUtf(collisionRule); - buf.writeVarInt(color); - buf.writeUtf(tokens2.isEmpty() ? prefix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(prefix), tokens2, context))); - buf.writeUtf(tokens3.isEmpty() ? suffix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(suffix), tokens3, context))); - if (entities != null) { - buf.writeStringList(entities); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetPlayerTeamPacket", e); - } - }; - - public static final BiConsumer BOSS_EVENT_1_20 = (user, event) -> { - if (!Config.interceptBossBar()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - UUID uuid = buf.readUUID(); - int actionType = buf.readVarInt(); - if (actionType == 0) { - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - float health = buf.readFloat(); - int color = buf.readVarInt(); - int division = buf.readVarInt(); - byte flag = buf.readByte(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUUID(uuid); - buf.writeVarInt(actionType); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - buf.writeFloat(health); - buf.writeVarInt(color); - buf.writeVarInt(division); - buf.writeByte(flag); - } else if (actionType == 3) { - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUUID(uuid); - buf.writeVarInt(actionType); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundBossEventPacket", e); - } - }; - - public static final BiConsumer BOSS_EVENT_1_20_3 = (user, event) -> { - if (!Config.interceptBossBar()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - UUID uuid = buf.readUUID(); - int actionType = buf.readVarInt(); - if (actionType == 0) { - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - float health = buf.readFloat(); - int color = buf.readVarInt(); - int division = buf.readVarInt(); - byte flag = buf.readByte(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUUID(uuid); - buf.writeVarInt(actionType); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeFloat(health); - buf.writeVarInt(color); - buf.writeVarInt(division); - buf.writeByte(flag); - } else if (actionType == 3) { - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUUID(uuid); - buf.writeVarInt(actionType); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundBossEventPacket", e); - } - }; - - public static final BiConsumer SET_OBJECTIVE_1_20 = (user, event) -> { - if (!Config.interceptScoreboard()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String objective = buf.readUtf(); - byte mode = buf.readByte(); - if (mode != 0 && mode != 2) return; - String displayName = buf.readUtf(); - int renderType = buf.readVarInt(); - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - buf.writeVarInt(renderType); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetObjectivePacket", e); - } - }; - - public static final BiConsumer SET_OBJECTIVE_1_20_3 = (user, event) -> { - if (!Config.interceptScoreboard()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String objective = buf.readUtf(); - byte mode = buf.readByte(); - if (mode != 0 && mode != 2) return; - Tag displayName = buf.readNbt(false); - if (displayName == null) return; - int renderType = buf.readVarInt(); - boolean optionalNumberFormat = buf.readBoolean(); - if (optionalNumberFormat) { - int format = buf.readVarInt(); - if (format == 0) { - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeVarInt(renderType); - buf.writeBoolean(true); - buf.writeVarInt(0); - } else if (format == 1) { - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - if (tokens.isEmpty()) return; - Tag style = buf.readNbt(false); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeVarInt(renderType); - buf.writeBoolean(true); - buf.writeVarInt(1); - buf.writeNbt(style, false); - } else if (format == 2) { - Tag fixed = buf.readNbt(false); - if (fixed == null) return; - Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(fixed.getAsString()); - if (tokens1.isEmpty() && tokens2.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeVarInt(renderType); - buf.writeBoolean(true); - buf.writeVarInt(2); - buf.writeNbt(tokens2.isEmpty() ? fixed : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(fixed), tokens2, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } - } else { - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeVarInt(renderType); - buf.writeBoolean(false); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetObjectivePacket", e); - } - }; - - public static final BiConsumer SYSTEM_CHAT_1_20 = (user, event) -> { - if (!Config.interceptSystemChat()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String jsonOrPlainString = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(jsonOrPlainString); - if (tokens.isEmpty()) return; - boolean overlay = buf.readBoolean(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(jsonOrPlainString), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - buf.writeBoolean(overlay); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSystemChatPacket", e); - } - }; - - public static final BiConsumer SYSTEM_CHAT_1_20_3 = (user, event) -> { - if (!Config.interceptSystemChat()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - boolean overlay = buf.readBoolean(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeBoolean(overlay); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSystemChatPacket", e); - } - }; - - public static final BiConsumer SET_SUBTITLE_TEXT_1_20 = (user, event) -> { - if (!Config.interceptTitle()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetSubtitleTextPacket", e); - } - }; - - public static final BiConsumer SET_SUBTITLE_TEXT_1_20_3 = (user, event) -> { - if (!Config.interceptTitle()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetSubtitleTextPacket", e); - } - }; - - public static final BiConsumer SET_TITLE_TEXT_1_20 = (user, event) -> { - if (!Config.interceptTitle()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetTitleTextPacket", e); - } - }; - - public static final BiConsumer SET_TITLE_TEXT_1_20_3 = (user, event) -> { - if (!Config.interceptTitle()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetTitleTextPacket", e); - } - }; - - public static final BiConsumer SET_ACTIONBAR_TEXT_1_20 = (user, event) -> { - if (!Config.interceptActionBar()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetActionBarTextPacket", e); - } - }; - - public static final BiConsumer SET_ACTIONBAR_TEXT_1_20_3 = (user, event) -> { - if (!Config.interceptActionBar()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetActionBarTextPacket", e); - } - }; - - public static final BiConsumer TAB_LIST_1_20 = (user, event) -> { - if (!Config.interceptTabList()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String json1 = buf.readUtf(); - String json2 = buf.readUtf(); - Map tokens1 = CraftEngine.instance().fontManager().matchTags(json1); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(json2); - if (tokens1.isEmpty() && tokens2.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); - buf.writeUtf(tokens1.isEmpty() ? json1 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json1), tokens1, context))); - buf.writeUtf(tokens2.isEmpty() ? json2 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json2), tokens2, context))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundTabListPacket", e); - } - }; - - public static final BiConsumer TAB_LIST_1_20_3 = (user, event) -> { - if (!Config.interceptTabList()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt1 = buf.readNbt(false); - if (nbt1 == null) return; - Tag nbt2 = buf.readNbt(false); - if (nbt2 == null) return; - Map tokens1 = CraftEngine.instance().fontManager().matchTags(nbt1.getAsString()); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(nbt2.getAsString()); - if (tokens1.isEmpty() && tokens2.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); - buf.writeNbt(tokens1.isEmpty() ? nbt1 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt1), tokens1, context)), false); - buf.writeNbt(tokens2.isEmpty() ? nbt2 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt2), tokens2, context)), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundTabListPacket", e); - } - }; - - public static final BiConsumer OPEN_SCREEN_1_20 = (user, event) -> { - if (!Config.interceptContainer()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - int containerId = buf.readVarInt(); - int type = buf.readVarInt(); - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(containerId); - buf.writeVarInt(type); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundOpenScreenPacket", e); - } - }; - - public static final BiConsumer OPEN_SCREEN_1_20_3 = (user, event) -> { - if (!Config.interceptContainer()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - int containerId = buf.readVarInt(); - int type = buf.readVarInt(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(containerId); - buf.writeVarInt(type); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundOpenScreenPacket", e); - } - }; - - public static final BiConsumer LEVEL_PARTICLE_1_21_4 = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - boolean overrideLimiter = buf.readBoolean(); - boolean alwaysShow = buf.readBoolean(); - double x = buf.readDouble(); - double y = buf.readDouble(); - double z = buf.readDouble(); - float xDist = buf.readFloat(); - float yDist = buf.readFloat(); - float zDist = buf.readFloat(); - float maxSpeed = buf.readFloat(); - int count = buf.readInt(); - Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); - if (option == null) return; - if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; - Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); - int id = BlockStateUtils.blockStateToId(blockState); - int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); - if (remapped == id) return; - Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); - Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeBoolean(overrideLimiter); - buf.writeBoolean(alwaysShow); - buf.writeDouble(x); - buf.writeDouble(y); - buf.writeDouble(z); - buf.writeFloat(xDist); - buf.writeFloat(yDist); - buf.writeFloat(zDist); - buf.writeFloat(maxSpeed); - buf.writeInt(count); - FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelParticlesPacket", e); - } - }; - - public static final BiConsumer LEVEL_PARTICLE_1_20_5 = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - boolean overrideLimiter = buf.readBoolean(); - double x = buf.readDouble(); - double y = buf.readDouble(); - double z = buf.readDouble(); - float xDist = buf.readFloat(); - float yDist = buf.readFloat(); - float zDist = buf.readFloat(); - float maxSpeed = buf.readFloat(); - int count = buf.readInt(); - Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); - if (option == null) return; - if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; - Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); - int id = BlockStateUtils.blockStateToId(blockState); - int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); - if (remapped == id) return; - Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); - Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeBoolean(overrideLimiter); - buf.writeDouble(x); - buf.writeDouble(y); - buf.writeDouble(z); - buf.writeFloat(xDist); - buf.writeFloat(yDist); - buf.writeFloat(zDist); - buf.writeFloat(maxSpeed); - buf.writeInt(count); - FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelParticlesPacket", e); - } - }; - - public static final BiConsumer LEVEL_PARTICLE_1_20 = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - Object particleType = FastNMS.INSTANCE.method$FriendlyByteBuf$readById(buf, MBuiltInRegistries.PARTICLE_TYPE); - boolean overrideLimiter = buf.readBoolean(); - double x = buf.readDouble(); - double y = buf.readDouble(); - double z = buf.readDouble(); - float xDist = buf.readFloat(); - float yDist = buf.readFloat(); - float zDist = buf.readFloat(); - float maxSpeed = buf.readFloat(); - int count = buf.readInt(); - Object option = FastNMS.INSTANCE.method$ClientboundLevelParticlesPacket$readParticle(buf, particleType); - if (option == null) return; - if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; - Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); - int id = BlockStateUtils.blockStateToId(blockState); - int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); - if (remapped == id) return; - Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); - Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeId(buf, remappedOption, MBuiltInRegistries.PARTICLE_TYPE); - buf.writeBoolean(overrideLimiter); - buf.writeDouble(x); - buf.writeDouble(y); - buf.writeDouble(z); - buf.writeFloat(xDist); - buf.writeFloat(yDist); - buf.writeFloat(zDist); - buf.writeFloat(maxSpeed); - buf.writeInt(count); - FastNMS.INSTANCE.method$ParticleOptions$writeToNetwork(remappedOption, buf); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelParticlesPacket", e); - } - }; - - public static final TriConsumer PLAYER_ACTION = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - BukkitServerPlayer player = (BukkitServerPlayer) user; - Player platformPlayer = player.platformPlayer(); - World world = platformPlayer.getWorld(); - Object blockPos = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$pos(packet); - BlockPos pos = LocationUtils.fromBlockPos(blockPos); - if (VersionHelper.isFolia()) { - platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { - try { - handlePlayerActionPacketOnMainThread(player, world, pos, packet); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPlayerActionPacket", e); - } - }, () -> {}); - } else { - handlePlayerActionPacketOnMainThread(player, world, pos, packet); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPlayerActionPacket", e); - } - }; - - private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) { - Object action = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$action(packet); - if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) { - Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); - Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, LocationUtils.toBlockPos(pos)); - int stateId = BlockStateUtils.blockStateToId(blockState); - // not a custom block - if (BlockStateUtils.isVanillaBlock(stateId)) { - if (Config.enableSoundSystem()) { - Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState); - if (BukkitBlockManager.instance().isBlockSoundRemoved(blockOwner)) { - player.startMiningBlock(pos, blockState, null); - return; - } - } - if (player.isMiningBlock()) { - player.stopMiningBlock(); - } else { - player.setClientSideCanBreakBlock(true); - } - return; - } - if (player.isAdventureMode()) { - if (Config.simplifyAdventureBreakCheck()) { - ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); - if (!player.canBreak(pos, state.vanillaBlockState().literalObject())) { - player.preventMiningBlock(); - return; - } - } else { - if (!player.canBreak(pos, null)) { - player.preventMiningBlock(); - return; - } - } - } - player.startMiningBlock(pos, blockState, BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId)); - } else if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$ABORT_DESTROY_BLOCK) { - if (player.isMiningBlock()) { - player.abortMiningBlock(); - } - } else if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$STOP_DESTROY_BLOCK) { - if (player.isMiningBlock()) { - player.stopMiningBlock(); - } - } - } - - public static final TriConsumer HELLO_C2S = (user, event, packet) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - String name = (String) NetworkReflections.methodHandle$ServerboundHelloPacket$nameGetter.invokeExact(packet); - player.setUnverifiedName(name); - if (VersionHelper.isOrAbove1_20_2()) { - UUID uuid = (UUID) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); - player.setUnverifiedUUID(uuid); - } else { - @SuppressWarnings("unchecked") - Optional uuid = (Optional) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); - if (uuid.isPresent()) { - player.setUnverifiedUUID(uuid.get()); - } else { - player.setUnverifiedUUID(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8))); - } - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundHelloPacket", e); - } - }; - - public static final TriConsumer SWING_HAND = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - BukkitServerPlayer player = (BukkitServerPlayer) user; - if (!player.isMiningBlock()) return; - Object hand = FastNMS.INSTANCE.field$ServerboundSwingPacket$hand(packet); - if (hand == CoreReflections.instance$InteractionHand$MAIN_HAND) { - player.onSwingHand(); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSwingPacket", e); - } - }; - - public static final TriConsumer USE_ITEM_ON = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - BukkitServerPlayer player = (BukkitServerPlayer) user; - if (player.isMiningBlock()) { - player.stopMiningBlock(); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundUseItemOnPacket", e); - } - }; - - public static final TriConsumer RESPAWN = (user, event, packet) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - player.clearView(); - Object dimensionKey; - if (!VersionHelper.isOrAbove1_20_2()) { - dimensionKey = NetworkReflections.methodHandle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet); - } else { - Object commonInfo = NetworkReflections.methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); - dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); - } - Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); - World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); - if (world != null) { - int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16; - player.setClientSideSectionCount(sectionCount); - player.setClientSideDimension(Key.of(location.toString())); - player.clearTrackedChunks(); - } else { - CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist"); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket", e); - } - }; - - public static final TriConsumer LOGIN = (user, event, packet) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - player.setConnectionState(ConnectionState.PLAY); - Object dimensionKey; - if (!VersionHelper.isOrAbove1_20_2()) { - dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet); - } else { - Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); - dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); - } - Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); - World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); - if (world != null) { - int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16; - player.setClientSideSectionCount(sectionCount); - player.setClientSideDimension(Key.of(location.toString())); - } else { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket: World " + location + " does not exist"); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket", e); - } - }; - - // 1.21.4- - // We can't find the best solution, we can only keep the feel as good as possible - // 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 (VersionHelper.isOrAbove1_21_4()) return; - if (!user.isOnline()) return; - BukkitServerPlayer player = (BukkitServerPlayer) user; - if (VersionHelper.isFolia()) { - player.platformPlayer().getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { - try { - handleSetCreativeSlotPacketOnMainThread(player, packet); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); - } - }, () -> {}); - } else { - handleSetCreativeSlotPacketOnMainThread(player, packet); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); - } - }; - - private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Throwable { - Player bukkitPlayer = player.platformPlayer(); - if (bukkitPlayer == null) return; - if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return; - int slot = VersionHelper.isOrAbove1_20_5() ? (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 (ItemStackUtils.isEmpty(item)) return; - if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) { - return; - } - double interactionRange = player.getCachedInteractionRange(); - // do ray trace to get current block - RayTraceResult result = bukkitPlayer.rayTraceBlocks(interactionRange, FluidCollisionMode.NEVER); - if (result == null) return; - Block hitBlock = result.getHitBlock(); - if (hitBlock == null) return; - ImmutableBlockState state = CraftEngineBlocks.getCustomBlockState(hitBlock); - // not a custom block - if (state == null || state.isEmpty()) return; - Key itemId = state.settings().itemId(); - // no item available - if (itemId == null) return; - Object vanillaBlock = FastNMS.INSTANCE.method$BlockState$getBlock(state.vanillaBlockState().literalObject()); - 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 (ItemStackUtils.isEmpty(itemStack)) { - CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); - return; - } - PlayerInventory inventory = bukkitPlayer.getInventory(); - int sameItemSlot = -1; - int emptySlot = -1; - for (int i = 0; i < 9 + 27; i++) { - ItemStack invItem = inventory.getItem(i); - if (ItemStackUtils.isEmpty(invItem)) { - if (emptySlot == -1 && i < 9) emptySlot = i; - continue; - } - if (invItem.getType().equals(itemStack.getType()) && invItem.getItemMeta().equals(itemStack.getItemMeta())) { - if (sameItemSlot == -1) sameItemSlot = i; - } - } - if (sameItemSlot != -1) { - if (sameItemSlot < 9) { - inventory.setHeldItemSlot(sameItemSlot); - ItemStack previousItem = inventory.getItem(slot - 36); - BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, previousItem)); - } else { - ItemStack sameItem = inventory.getItem(sameItemSlot); - int finalSameItemSlot = sameItemSlot; - BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> { - inventory.setItem(finalSameItemSlot, new ItemStack(Material.AIR)); - inventory.setItem(slot - 36, sameItem); - }); - } - } else { - if (item.getAmount() == 1) { - if (ItemStackUtils.isEmpty(inventory.getItem(slot - 36))) { - BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack)); - return; - } - if (emptySlot != -1) { - inventory.setHeldItemSlot(emptySlot); - inventory.setItem(emptySlot, itemStack); - } else { - BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack)); - } - } - } - } - - // 1.21.4+ - public static final TriConsumer PICK_ITEM_FROM_BLOCK = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - Player player = (Player) user.platformPlayer(); - if (player == null) return; - Object pos = NetworkReflections.methodHandle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet); - if (VersionHelper.isFolia()) { - int x = FastNMS.INSTANCE.field$Vec3i$x(pos); - int z = FastNMS.INSTANCE.field$Vec3i$z(pos); - BukkitCraftEngine.instance().scheduler().sync().run(() -> { - try { - handlePickItemFromBlockPacketOnMainThread(player, pos); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e); - } - }, player.getWorld(), x >> 4, z >> 4); - } else { - BukkitCraftEngine.instance().scheduler().sync().run(() -> { - try { - handlePickItemFromBlockPacketOnMainThread(player, pos); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e); - } - }); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e); - } - }; - - private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Throwable { - Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); - Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos); - ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); - if (state == null) return; - Key itemId = state.settings().itemId(); - if (itemId == null) return; - pickItem(player, itemId, pos, null); - } - - // 1.21.4+ - public static final TriConsumer PICK_ITEM_FROM_ENTITY = (user, event, packet) -> { - try { - int entityId = (int) NetworkReflections.methodHandle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet); - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); - if (furniture == null) return; - Player player = (Player) user.platformPlayer(); - if (player == null) return; - if (VersionHelper.isFolia()) { - player.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { - try { - handlePickItemFromEntityOnMainThread(player, furniture); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e); - } - }, () -> {}); - } else { - BukkitCraftEngine.instance().scheduler().sync().run(() -> { - try { - handlePickItemFromEntityOnMainThread(player, furniture); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e); - } - }); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e); - } - }; - - private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Throwable { - Key itemId = furniture.config().settings().itemId(); - if (itemId == null) return; - pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity())); - } - - private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws Throwable { - ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, BukkitCraftEngine.instance().adapt(player)); - if (itemStack == null) { - CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); - return; - } - assert CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem != null; - if (VersionHelper.isOrAbove1_21_5()) { - CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), - FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true); - } else { - CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); - } - } - - public static final BiConsumer ADD_ENTITY = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - buf.readVarInt(); - buf.readUUID(); - int type = buf.readVarInt(); - ADD_ENTITY_HANDLERS[type].accept(user, event); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e); - } - }; - - // 1.21.2+ - public static final TriConsumer SYNC_ENTITY_POSITION = (user, event, packet) -> { - try { - int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); - EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); - if (handler != null) { - handler.handleSyncEntityPosition(user, event, packet); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityPositionSyncPacket", e); - } - }; - - public static final BiConsumer REMOVE_ENTITY = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - boolean isChange = false; - IntList intList = buf.readIntIdList(); - for (int i = 0, size = intList.size(); i < size; i++) { - int entityId = intList.getInt(i); - EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); - if (handler != null && handler.handleEntitiesRemove(intList)) { - isChange = true; - } - } - if (isChange) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeIntIdList(intList); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundRemoveEntitiesPacket", e); - } - }; - - public static final BiConsumer INTERACT_ENTITY = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - int entityId = BukkitNetworkManager.hasModelEngine() ? - CraftEngine.instance().compatibilityManager().interactionToBaseEntity(buf.readVarInt()) : - buf.readVarInt(); - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); - if (furniture == null) return; - int actionType = buf.readVarInt(); - BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; - if (serverPlayer.isSpectatorMode()) return; - Player platformPlayer = serverPlayer.platformPlayer(); - Location location = furniture.baseEntity().getLocation(); - - Runnable mainThreadTask; - if (actionType == 1) { - // ATTACK - boolean usingSecondaryAction = buf.readBoolean(); - if (entityId != furniture.baseEntityId()) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(furniture.baseEntityId()); - buf.writeVarInt(actionType); - buf.writeBoolean(usingSecondaryAction); - } - - mainThreadTask = () -> { - // todo 冒险模式破坏工具白名单 - if (serverPlayer.isAdventureMode() || - !furniture.isValid()) return; - - // todo 重构家具时候注意,需要准备加载好的hitbox类,以获取hitbox坐标 - if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { - return; - } - - FurnitureAttemptBreakEvent preBreakEvent = new FurnitureAttemptBreakEvent(serverPlayer.platformPlayer(), furniture); - if (EventUtils.fireAndCheckCancel(preBreakEvent)) - return; - - if (!BukkitCraftEngine.instance().antiGriefProvider().canBreak(platformPlayer, location)) - return; - - FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture); - if (EventUtils.fireAndCheckCancel(breakEvent)) - return; - - Cancellable cancellable = Cancellable.of(breakEvent::isCancelled, breakEvent::setCancelled); - // execute functions - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withParameter(DirectContextParameters.FURNITURE, furniture) - .withParameter(DirectContextParameters.EVENT, cancellable) - .withParameter(DirectContextParameters.HAND, InteractionHand.MAIN_HAND) - .withParameter(DirectContextParameters.ITEM_IN_HAND, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)) - .withParameter(DirectContextParameters.POSITION, furniture.position()) - ); - furniture.config().execute(context, EventTrigger.LEFT_CLICK); - furniture.config().execute(context, EventTrigger.BREAK); - if (cancellable.isCancelled()) { - return; - } - - CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); - }; - } else if (actionType == 2) { - // INTERACT_AT - float x = buf.readFloat(); - float y = buf.readFloat(); - float z = buf.readFloat(); - // todo 这个是错误的,这是实体的相对位置而非绝对位置 - Location interactionPoint = new Location(platformPlayer.getWorld(), x, y, z); - InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; - boolean usingSecondaryAction = buf.readBoolean(); - if (entityId != furniture.baseEntityId()) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(furniture.baseEntityId()); - buf.writeVarInt(actionType); - buf.writeFloat(x).writeFloat(y).writeFloat(z); - buf.writeVarInt(hand == InteractionHand.MAIN_HAND ? 0 : 1); - buf.writeBoolean(usingSecondaryAction); - } - - mainThreadTask = () -> { - if (!furniture.isValid()) { - return; - } - - // todo 重构家具时候注意,需要准备加载好的hitbox类,以获取hitbox坐标 - if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { - return; - } - - FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint); - if (EventUtils.fireAndCheckCancel(interactEvent)) { - return; - } - - Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); - Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled); - // execute functions - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withParameter(DirectContextParameters.EVENT, cancellable) - .withParameter(DirectContextParameters.FURNITURE, furniture) - .withParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) - .withParameter(DirectContextParameters.HAND, hand) - .withParameter(DirectContextParameters.POSITION, furniture.position()) - ); - furniture.config().execute(context, EventTrigger.RIGHT_CLICK); - if (cancellable.isCancelled()) { - return; - } - - // 必须从网络包层面处理,否则无法获取交互的具体实体 - if (serverPlayer.isSecondaryUseActive() && !itemInHand.isEmpty()) { - // try placing another furniture above it - AABB hitBox = furniture.aabbByEntityId(entityId); - if (hitBox == null) return; - Optional> optionalCustomItem = itemInHand.getCustomItem(); - Location eyeLocation = platformPlayer.getEyeLocation(); - Vector direction = eyeLocation.getDirection(); - Location endLocation = eyeLocation.clone(); - endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); - Optional result = hitBox.clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation)); - if (result.isEmpty()) { - return; - } - EntityHitResult hitResult = result.get(); - if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) { - for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) { - if (behavior instanceof FurnitureItemBehavior) { - behavior.useOnBlock(new UseOnContext(serverPlayer, InteractionHand.MAIN_HAND, new BlockHitResult(hitResult.hitLocation(), hitResult.direction(), BlockPos.fromVec3d(hitResult.hitLocation()), false))); - return; - } - } - } - // now simulate vanilla item behavior - serverPlayer.setResendSound(); - FastNMS.INSTANCE.simulateInteraction( - serverPlayer.serverPlayer(), - DirectionUtils.toNMSDirection(hitResult.direction()), - hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z, - LocationUtils.toBlockPos(hitResult.blockPos()) - ); - } else { - if (!serverPlayer.isSecondaryUseActive()) { - furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { - if (furniture.tryOccupySeat(seatPos)) { - furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos); - } - }); - } - } - }; - } else if (actionType == 0) { - int hand = buf.readVarInt(); - boolean usingSecondaryAction = buf.readBoolean(); - if (entityId != furniture.baseEntityId()) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(furniture.baseEntityId()); - buf.writeVarInt(actionType); - buf.writeVarInt(hand); - buf.writeBoolean(usingSecondaryAction); - } - return; - } else { - return; - } - - if (VersionHelper.isFolia()) { - platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), t -> mainThreadTask.run(), () -> {}); - } else { - BukkitCraftEngine.instance().scheduler().executeSync(mainThreadTask); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundInteractPacket", e); - } - }; - - public static final BiConsumer SOUND = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - if (id == 0) { - Key soundId = buf.readKey(); - Float range = null; - if (buf.readBoolean()) { - range = buf.readFloat(); - } - int source = buf.readVarInt(); - int x = buf.readInt(); - int y = buf.readInt(); - int z = buf.readInt(); - float volume = buf.readFloat(); - float pitch = buf.readFloat(); - long seed = buf.readLong(); - Key mapped = BukkitBlockManager.instance().replaceSoundIfExist(soundId); - if (mapped != null) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(0); - buf.writeKey(mapped); - if (range != null) { - buf.writeBoolean(true); - buf.writeFloat(range); - } else { - buf.writeBoolean(false); - } - buf.writeVarInt(source); - buf.writeInt(x); - buf.writeInt(y); - buf.writeInt(z); - buf.writeFloat(volume); - buf.writeFloat(pitch); - buf.writeLong(seed); - } - } else { - Optional optionalSound = FastNMS.INSTANCE.method$IdMap$byId(MBuiltInRegistries.SOUND_EVENT, id - 1); - if (optionalSound.isEmpty()) return; - Object soundEvent = optionalSound.get(); - Key soundId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$SoundEvent$location(soundEvent)); - int source = buf.readVarInt(); - int x = buf.readInt(); - int y = buf.readInt(); - int z = buf.readInt(); - float volume = buf.readFloat(); - float pitch = buf.readFloat(); - long seed = buf.readLong(); - Key mapped = BukkitBlockManager.instance().replaceSoundIfExist(soundId); - if (mapped != null) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(0); - Object newId = KeyUtils.toResourceLocation(mapped); - Object newSoundEvent = FastNMS.INSTANCE.constructor$SoundEvent(newId, FastNMS.INSTANCE.method$SoundEvent$fixedRange(soundEvent)); - FastNMS.INSTANCE.method$SoundEvent$directEncode(buf, newSoundEvent); - buf.writeVarInt(source); - buf.writeInt(x); - buf.writeInt(y); - buf.writeInt(z); - buf.writeFloat(volume); - buf.writeFloat(pitch); - buf.writeLong(seed); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSoundPacket", e); - } - }; - - // we handle it on packet level to prevent it from being captured by plugins - public static final TriConsumer RENAME_ITEM = (user, event, packet) -> { - try { - if (!Config.filterAnvil()) return; - if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) { - return; - } - String message = (String) NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet); - if (message != null && !message.isEmpty()) { - // check bypass - FontManager manager = CraftEngine.instance().fontManager(); - IllegalCharacterProcessResult result = manager.processIllegalCharacters(message); - if (result.has()) { - try { - NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text()); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to replace chat", e); - } - } - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e); - } - }; - - // we handle it on packet level to prevent it from being captured by plugins - public static final TriConsumer SIGN_UPDATE = (user, event, packet) -> { - try { - if (!Config.filterSign()) return; - // check bypass - if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) { - return; - } - String[] lines = (String[]) NetworkReflections.methodHandle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet); - FontManager manager = CraftEngine.instance().fontManager(); - if (!manager.isDefaultFontInUse()) return; - for (int i = 0; i < lines.length; i++) { - String line = lines[i]; - if (line != null && !line.isEmpty()) { - IllegalCharacterProcessResult result = manager.processIllegalCharacters(line); - if (result.has()) { - lines[i] = result.text(); - } - } - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSignUpdatePacket", e); - } - }; - - // we handle it on packet level to prevent it from being captured by plugins - @SuppressWarnings("unchecked") - public static final TriConsumer EDIT_BOOK = (user, event, packet) -> { - try { - if (!Config.filterBook()) return; - FontManager manager = CraftEngine.instance().fontManager(); - if (!manager.isDefaultFontInUse()) return; - // check bypass - if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_BOOK)) { - return; - } - - boolean changed = false; - - List pages = (List) NetworkReflections.methodHandle$ServerboundEditBookPacket$pagesGetter.invokeExact(packet); - List newPages = new ArrayList<>(pages.size()); - Optional title = (Optional) NetworkReflections.methodHandle$ServerboundEditBookPacket$titleGetter.invokeExact(packet); - Optional newTitle; - - if (title.isPresent()) { - String titleStr = title.get(); - Pair result = processClientString(titleStr, manager); - newTitle = Optional.of(result.right()); - if (result.left()) { - changed = true; - } - } else { - newTitle = Optional.empty(); - } - - for (String page : pages) { - Pair result = processClientString(page, manager); - newPages.add(result.right()); - if (result.left()) { - changed = true; - } - } - - if (changed) { - Object newPacket = NetworkReflections.constructor$ServerboundEditBookPacket.newInstance( - (int) NetworkReflections.methodHandle$ServerboundEditBookPacket$slotGetter.invokeExact(packet), - newPages, - newTitle - ); - event.replacePacket(newPacket); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundEditBookPacket", e); - } - }; - - private static Pair processClientString(String original, FontManager manager) { - if (original.isEmpty()) { - return Pair.of(false, original); - } - int[] codepoints = CharacterUtils.charsToCodePoints(original.toCharArray()); - int[] newCodepoints = new int[codepoints.length]; - boolean hasIllegal = false; - for (int i = 0; i < codepoints.length; i++) { - int codepoint = codepoints[i]; - if (manager.isIllegalCodepoint(codepoint)) { - newCodepoints[i] = '*'; - hasIllegal = true; - } else { - newCodepoints[i] = codepoint; - } - } - return hasIllegal ? Pair.of(true, new String(newCodepoints, 0, newCodepoints.length)) : Pair.of(false, original); - } - - public static final TriConsumer CUSTOM_PAYLOAD_1_20_2 = (user, event, packet) -> { - try { - if (!VersionHelper.isOrAbove1_20_2()) return; - Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); - Payload clientPayload; - if (VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { - clientPayload = DiscardedPayload.from(payload); - } else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$ServerboundCustomPayloadPacket$UnknownPayload.isInstance(payload)) { - clientPayload = UnknownPayload.from(payload); - } else { - return; - } - if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return; - PayloadHelper.handleReceiver(clientPayload, user); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e); - } - }; - - public static final BiConsumer CUSTOM_PAYLOAD_1_20 = (user, event) -> { - try { - if (VersionHelper.isOrAbove1_20_2()) return; - FriendlyByteBuf byteBuf = event.getBuffer(); - Key key = byteBuf.readKey(); - if (!key.equals(NetworkManager.MOD_CHANNEL_KEY)) return; - PayloadHelper.handleReceiver(new UnknownPayload(key, byteBuf.readBytes(byteBuf.readableBytes())), user); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e); - } - }; - - @SuppressWarnings("unchecked") - public static final BiConsumer SET_ENTITY_DATA = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - EntityPacketHandler handler = user.entityPacketHandlers().get(id); - if (handler != null) { - handler.handleSetEntityData(serverPlayer, event); - return; - } - if (Config.interceptEntityName()) { - 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 != BaseEntityData.CustomName.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); - component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); - 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); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); - } - }; - - public static final BiConsumer SET_SCORE_1_20_3 = (user, event) -> { - try { - if (!Config.interceptSetScore()) return; - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - boolean isChanged = false; - FriendlyByteBuf buf = event.getBuffer(); - String owner = buf.readUtf(); - String objectiveName = buf.readUtf(); - int score = buf.readVarInt(); - boolean hasDisplay = buf.readBoolean(); - Tag displayName = null; - if (hasDisplay) { - displayName = buf.readNbt(false); - } - outside: - if (displayName != null) { - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - if (tokens.isEmpty()) break outside; - Component component = AdventureHelper.tagToComponent(displayName); - component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); - displayName = AdventureHelper.componentToTag(component); - isChanged = true; - } - boolean hasNumberFormat = buf.readBoolean(); - int format = -1; - Tag style = null; - Tag fixed = null; - if (hasNumberFormat) { - format = buf.readVarInt(); - if (format == 0) { - if (displayName == null) return; - } else if (format == 1) { - if (displayName == null) return; - style = buf.readNbt(false); - } else if (format == 2) { - fixed = buf.readNbt(false); - if (fixed == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(fixed.getAsString()); - if (tokens.isEmpty() && !isChanged) return; - if (!tokens.isEmpty()) { - Component component = AdventureHelper.tagToComponent(fixed); - component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); - fixed = AdventureHelper.componentToTag(component); - isChanged = true; - } - } - } - if (isChanged) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(owner); - buf.writeUtf(objectiveName); - buf.writeVarInt(score); - if (hasDisplay) { - buf.writeBoolean(true); - buf.writeNbt(displayName, false); - } else { - buf.writeBoolean(false); - } - if (hasNumberFormat) { - buf.writeBoolean(true); - buf.writeVarInt(format); - if (format == 1) { - buf.writeNbt(style, false); - } else if (format == 2) { - buf.writeNbt(fixed, false); - } - } else { - buf.writeBoolean(false); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetScorePacket", e); - } - }; - - public static final BiConsumer CONTAINER_SET_CONTENT = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - int containerId = buf.readContainerId(); - int stateId = buf.readVarInt(); - int listSize = buf.readVarInt(); - List items = new ArrayList<>(listSize); - boolean changed = false; - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - for (int i = 0; i < listSize; i++) { - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); - if (optional.isPresent()) { - items.add(optional.get()); - changed = true; - } else { - items.add(itemStack); - } - } - ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - ItemStack newCarriedItem = carriedItem; - Optional optional = BukkitItemManager.instance().s2c(carriedItem, serverPlayer); - if (optional.isPresent()) { - changed = true; - newCarriedItem = optional.get(); - } - if (!changed) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeContainerId(containerId); - buf.writeVarInt(stateId); - buf.writeVarInt(listSize); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - for (ItemStack itemStack : items) { - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); - } - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newCarriedItem); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundContainerSetContentPacket", e); - } - }; - - public static final BiConsumer CONTAINER_SET_SLOT = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - int containerId = buf.readContainerId(); - int stateId = buf.readVarInt(); - int slot = buf.readShort(); - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - 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(); - buf.writeVarInt(event.packetID()); - buf.writeContainerId(containerId); - buf.writeVarInt(stateId); - buf.writeShort(slot); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundContainerSetSlotPacket", e); - } - }; - - public static final BiConsumer SET_CURSOR_ITEM = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetCursorItemPacket", e); - } - }; - - public static final BiConsumer SET_EQUIPMENT = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - boolean changed = false; - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - int entity = buf.readVarInt(); - List> slots = Lists.newArrayList(); - int slotMask; - do { - slotMask = buf.readByte(); - Object equipmentSlot = CoreReflections.instance$EquipmentSlot$values[slotMask & 127]; - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); - if (optional.isPresent()) { - changed = true; - itemStack = optional.get(); - } - slots.add(com.mojang.datafixers.util.Pair.of(equipmentSlot, itemStack)); - } while ((slotMask & -128) != 0); - if (changed) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(entity); - int i = slots.size(); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - for (int j = 0; j < i; ++j) { - com.mojang.datafixers.util.Pair pair = slots.get(j); - Enum equipmentSlot = (Enum) pair.getFirst(); - boolean bl = j != i - 1; - int k = equipmentSlot.ordinal(); - buf.writeByte(bl ? k | -128 : k); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond()); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEquipmentPacket", e); - } - }; - - public static final BiConsumer SET_PLAYER_INVENTORY_1_21_2 = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - int slot = buf.readVarInt(); - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(slot); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetPlayerInventoryPacket", e); - } - }; - - public static final BiConsumer SET_CREATIVE_MODE_SLOT = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - if (!serverPlayer.isCreativeMode()) return; - FriendlyByteBuf buf = event.getBuffer(); - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - short slotNum = buf.readShort(); - ItemStack itemStack; - try { - itemStack = VersionHelper.isOrAbove1_20_5() ? - FastNMS.INSTANCE.method$FriendlyByteBuf$readUntrustedItem(friendlyBuf) : FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - } catch (Exception e) { - return; - } - BukkitItemManager.instance().c2s(itemStack).ifPresent((newItemStack) -> { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeShort(slotNum); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - if (VersionHelper.isOrAbove1_20_5()) { - FastNMS.INSTANCE.method$FriendlyByteBuf$writeUntrustedItem(newFriendlyBuf, newItemStack); - } else { - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); - } - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); - } - }; - - // 因为不能走编码器只能替换对象 - public static final TriConsumer CONTAINER_CLICK_1_21_5 = (user, event, packet) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - int containerId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$containerId(packet); - int stateId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$stateId(packet); - short slotNum = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$slotNum(packet); - byte buttonNum = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$buttonNum(packet); - Object clickType = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$clickType(packet); - @SuppressWarnings("unchecked") - Int2ObjectMap changedSlots = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$changedSlots(packet); - Int2ObjectMap newChangedSlots = new Int2ObjectOpenHashMap<>(changedSlots.size()); - for (Int2ObjectMap.Entry entry : changedSlots.int2ObjectEntrySet()) { - newChangedSlots.put(entry.getIntKey(), FastNMS.INSTANCE.constructor$InjectedHashedStack(entry.getValue(), player)); - } - Object carriedItem = FastNMS.INSTANCE.constructor$InjectedHashedStack(FastNMS.INSTANCE.field$ServerboundContainerClickPacket$carriedItem(packet), player); - event.replacePacket(FastNMS.INSTANCE.constructor$ServerboundContainerClickPacket(containerId, stateId, slotNum, buttonNum, clickType, Int2ObjectMaps.unmodifiable(newChangedSlots), carriedItem)); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundContainerClickPacket", e); - } - }; - - public static final BiConsumer CONTAINER_CLICK_1_20 = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - boolean changed = false; - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - int containerId = buf.readContainerId(); - int stateId = buf.readVarInt(); - short slotNum = buf.readShort(); - byte buttonNum = buf.readByte(); - int clickType = buf.readVarInt(); - int i = buf.readVarInt(); - Int2ObjectMap changedSlots = new Int2ObjectOpenHashMap<>(i); - for (int j = 0; j < i; ++j) { - int k = buf.readShort(); - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - Optional optional = BukkitItemManager.instance().c2s(itemStack); - if (optional.isPresent()) { - changed = true; - itemStack = optional.get(); - } - changedSlots.put(k, itemStack); - } - ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - Optional optional = BukkitItemManager.instance().c2s(carriedItem); - if (optional.isPresent()) { - changed = true; - carriedItem = optional.get(); - } - if (changed) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeContainerId(containerId); - buf.writeVarInt(stateId); - buf.writeShort(slotNum); - buf.writeByte(buttonNum); - buf.writeVarInt(clickType); - buf.writeVarInt(changedSlots.size()); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - changedSlots.forEach((k, v) -> { - buf.writeShort(k); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, v); - }); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, carriedItem); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundContainerClickPacket", e); - } - }; - - public static final TriConsumer RESOURCE_PACK_RESPONSE = (user, event, packet) -> { - try { - 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 (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); - } - }; - - public static final TriConsumer ENTITY_EVENT = (user, event, packet) -> { - try { - Object player = user.serverPlayer(); - if (player == null) return; - int entityId = (int) NetworkReflections.methodHandle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet); - if (entityId != FastNMS.INSTANCE.method$Entity$getId(player)) return; - byte eventId = (byte) NetworkReflections.methodHandle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet); - if (eventId >= 24 && eventId <= 28) { - CraftEngine.instance().fontManager().refreshEmojiSuggestions(user.uuid()); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityEventPacket", e); - } - }; - - public static final TriConsumer MOVE_POS_AND_ROTATE_ENTITY = (user, event, packet) -> { - try { - int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); - } - EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); - if (handler != null) { - handler.handleMoveAndRotate(user, event, packet); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); - } - }; - - public static final TriConsumer MOVE_POS_ENTITY = (user, event, packet) -> { - try { - int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); - EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); - if (handler != null) { - handler.handleMove(user, event, packet); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e); - } - }; - - public static final TriConsumer ROTATE_HEAD = (user, event, packet) -> { - try { - int entityId = (int) NetworkReflections.methodHandle$ClientboundRotateHeadPacket$entityIdGetter.invokeExact(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundRotateHeadPacket", e); - } - }; - - public static final TriConsumer SET_ENTITY_MOTION = (user, event, packet) -> { - try { - if (!VersionHelper.isOrAbove1_21_6()) return; - int entityId = (int) NetworkReflections.methodHandle$ClientboundSetEntityMotionPacket$idGetter.invokeExact(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); - } - } catch (Throwable e) { - 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); - - // 检查用户UUID是否已经校验 - if (!user.isUUIDVerified()) { - if (Config.strictPlayerUuidValidation()) { - TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString()); - user.kick(Component.translatable("disconnect.loginFailedInfo").arguments(Component.translatable("argument.uuid.invalid"))); - return; - } - if (Config.debugResourcePack()) { - TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString()); - } - } - - // 取消 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.setVerifiedName(gameProfile.getName()); - user.setVerifiedUUID(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 { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - boolean reset = buf.readBoolean(); - List added = buf.readCollection(ArrayList::new, byteBuf -> { - AdvancementHolder holder = AdvancementHolder.read(byteBuf); - holder.applyClientboundData(serverPlayer); - 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/handler/BlockDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java index 953f45bf5..fa86d8d8f 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 @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.entity.data.BlockDisplayEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -36,12 +36,7 @@ public class BlockDisplayPacketHandler implements EntityPacketHandler { if (entityDataId == BlockDisplayEntityData.DisplayedBlock.id()) { Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); int stateId = BlockStateUtils.blockStateToId(blockState); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId= BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) continue; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( 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 80a4c20cd..ecc0a03d5 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 @@ -41,7 +41,7 @@ public class CommonItemPacketHandler implements EntityPacketHandler { continue; } ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); - Optional optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user); + Optional optional = BukkitItemManager.instance().s2c(itemStack, user); if (optional.isEmpty()) continue; isChanged = true; itemStack = optional.get(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java index 3d5561c01..760820024 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.entity.data.EnderManData; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -38,12 +38,7 @@ public class EndermanPacketHandler implements EntityPacketHandler { Optional blockState = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (blockState.isEmpty()) continue; int stateId = BlockStateUtils.blockStateToId(blockState.get()); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId = BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) continue; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java index 653b1f18a..718946298 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.entity.data.AbstractMinecartData; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -79,12 +79,7 @@ public class MinecartPacketHandler implements EntityPacketHandler { Optional blockState = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (blockState.isEmpty()) return null; int stateId = BlockStateUtils.blockStateToId(blockState.get()); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId = BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) return null; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); return FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( @@ -100,12 +95,7 @@ public class MinecartPacketHandler implements EntityPacketHandler { public Object handle(NetWorkUser user, Object packedItem, int entityDataId) { if (entityDataId != AbstractMinecartData.DisplayBlock.id()) return null; int stateId = (int) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId = BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) return null; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); return FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, newStateId); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java index ef3178e21..6fab87f02 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.entity.data.PrimedTntData; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -36,12 +36,7 @@ public class PrimedTNTPacketHandler implements EntityPacketHandler { if (entityDataId == PrimedTntData.BlockState.id()) { Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); int stateId = BlockStateUtils.blockStateToId(blockState); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId = BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) continue; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( 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 deleted file mode 100644 index e8d383aec..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.momirealms.craftengine.bukkit.plugin.network.id; - -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.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.VersionHelper; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class PacketIdFinder { - private static final Map> gamePacketIdsByName = new HashMap<>(); - private static final Map, Integer>> gamePacketIdsByClazz = new HashMap<>(); - private static final int maxC2SPacketId; - private static final int maxS2CPacketId; - - static { - try { - if (VersionHelper.isOrAbove1_21()) { - Object packetReport = CoreReflections.constructor$PacketReport.newInstance((Object) null); - JsonElement jsonElement = (JsonElement) CoreReflections.method$PacketReport$serializePackets.invoke(packetReport); - 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()) { - ids.put(entry2.getKey(), entry2.getValue().getAsJsonObject().get("protocol_id").getAsInt()); - } - } - } else if (VersionHelper.isOrAbove1_20_5()) { - gamePacketIdsByName.putAll(FastNMS.INSTANCE.gamePacketIdsByName()); - } else { - gamePacketIdsByClazz.putAll(FastNMS.INSTANCE.gamePacketIdsByClazz()); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to get packets", e); - } - maxS2CPacketId = calculateMaxId("clientbound"); - maxC2SPacketId = calculateMaxId("serverbound"); - } - - private static int calculateMaxId(String direction) { - if (VersionHelper.isOrAbove1_20_5()) { - return gamePacketIdsByName.getOrDefault(direction, Collections.emptyMap()).size(); - } else { - return gamePacketIdsByClazz.getOrDefault(direction, Collections.emptyMap()).size(); - } - } - - public static int c2sGamePackets() { - return maxC2SPacketId; - } - - public static int s2cGamePackets() { - return maxS2CPacketId; - } - - public static int clientboundByName(String packetName) { - return gamePacketIdsByName.get("clientbound").getOrDefault(packetName, -1); - } - - public static int clientboundByClazz(Class clazz) { - return gamePacketIdsByClazz.get("clientbound").getOrDefault(clazz, -1); - } - - public static int serverboundByName(String packetName) { - return gamePacketIdsByName.get("serverbound").getOrDefault(packetName, -1); - } - - public static int serverboundByClazz(Class clazz) { - return gamePacketIdsByClazz.get("serverbound").getOrDefault(clazz, -1); - } -} 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 99eb1c449..8b33c8fef 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 @@ -2,181 +2,183 @@ package net.momirealms.craftengine.bukkit.plugin.network.id; import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.core.plugin.network.PacketFlow; public class PacketIds1_20 implements PacketIds { @Override public int clientboundBlockUpdatePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundBlockUpdatePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundBlockUpdatePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSectionBlocksUpdatePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSectionBlocksUpdatePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSectionBlocksUpdatePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelParticlesPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundLevelParticlesPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundLevelParticlesPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelEventPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundLevelEventPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundLevelEventPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundAddEntityPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundAddEntityPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundAddEntityPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundOpenScreenPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundOpenScreenPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundOpenScreenPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSoundPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSoundPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSoundPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundRemoveEntitiesPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundRemoveEntitiesPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundRemoveEntitiesPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetEntityDataPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetEntityDataPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetEntityDataPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetTitleTextPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetTitleTextPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetTitleTextPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetSubtitleTextPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetSubtitleTextPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetSubtitleTextPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetActionBarTextPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetActionBarTextPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetActionBarTextPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundBossEventPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundBossEventPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundBossEventPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSystemChatPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSystemChatPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSystemChatPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundTabListPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundTabListPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundTabListPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetPlayerTeamPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetPlayerTeamPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetPlayerTeamPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetObjectivePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetObjectivePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetObjectivePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelChunkWithLightPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundLevelChunkWithLightPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundLevelChunkWithLightPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundPlayerInfoUpdatePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundPlayerInfoUpdatePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundPlayerInfoUpdatePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetScorePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetScorePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetScorePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundContainerSetContentPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundContainerSetContentPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundContainerSetContentPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundContainerSetSlotPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundContainerSetSlotPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundContainerSetSlotPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetCursorItemPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetCursorItemPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetCursorItemPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetEquipmentPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetEquipmentPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetEquipmentPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetPlayerInventoryPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetPlayerInventoryPacket); - } - - @Override - public int serverboundContainerClickPacket() { - return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundContainerClickPacket); - } - - @Override - public int serverboundSetCreativeModeSlotPacket() { - return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket); - } - - @Override - public int clientboundBlockEventPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundBlockEventPacket); - } - - @Override - public int serverboundInteractPacket() { - return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundInteractPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetPlayerInventoryPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundRecipeBookAddPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundRecipeBookAddPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundRecipeBookAddPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundPlaceGhostRecipePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundPlaceGhostRecipePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundPlaceGhostRecipePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundUpdateRecipesPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateRecipesPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundUpdateRecipesPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundUpdateAdvancementsPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateAdvancementsPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundUpdateAdvancementsPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundForgetLevelChunkPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundForgetLevelChunkPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundForgetLevelChunkPacket, PacketFlow.CLIENTBOUND); + } + + @Override + public int clientboundBlockEventPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundBlockEventPacket, PacketFlow.CLIENTBOUND); + } + + @Override + public int serverboundContainerClickPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundContainerClickPacket, PacketFlow.SERVERBOUND); + } + + @Override + public int serverboundSetCreativeModeSlotPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket, PacketFlow.SERVERBOUND); + } + + + @Override + public int serverboundInteractPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundInteractPacket, PacketFlow.SERVERBOUND); } @Override public int serverboundCustomPayloadPacket() { - return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundCustomPayloadPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundCustomPayloadPacket, PacketFlow.SERVERBOUND); } } 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 70596861c..9aea4a3df 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 @@ -1,181 +1,182 @@ package net.momirealms.craftengine.bukkit.plugin.network.id; import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; +import net.momirealms.craftengine.core.plugin.network.PacketFlow; public class PacketIds1_20_5 implements PacketIds { @Override public int clientboundBlockUpdatePacket() { - return PacketIdFinder.clientboundByName("minecraft:block_update"); + return PlayPacketIdHelper.byName("minecraft:block_update", PacketFlow.CLIENTBOUND); } @Override public int clientboundSectionBlocksUpdatePacket() { - return PacketIdFinder.clientboundByName("minecraft:section_blocks_update"); + return PlayPacketIdHelper.byName("minecraft:section_blocks_update", PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelParticlesPacket() { - return PacketIdFinder.clientboundByName("minecraft:level_particles"); + return PlayPacketIdHelper.byName("minecraft:level_particles", PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelEventPacket() { - return PacketIdFinder.clientboundByName("minecraft:level_event"); + return PlayPacketIdHelper.byName("minecraft:level_event", PacketFlow.CLIENTBOUND); } @Override public int clientboundAddEntityPacket() { - return PacketIdFinder.clientboundByName("minecraft:add_entity"); + return PlayPacketIdHelper.byName("minecraft:add_entity", PacketFlow.CLIENTBOUND); } @Override public int clientboundOpenScreenPacket() { - return PacketIdFinder.clientboundByName("minecraft:open_screen"); + return PlayPacketIdHelper.byName("minecraft:open_screen", PacketFlow.CLIENTBOUND); } @Override public int clientboundSoundPacket() { - return PacketIdFinder.clientboundByName("minecraft:sound"); + return PlayPacketIdHelper.byName("minecraft:sound", PacketFlow.CLIENTBOUND); } @Override public int clientboundRemoveEntitiesPacket() { - return PacketIdFinder.clientboundByName("minecraft:remove_entities"); + return PlayPacketIdHelper.byName("minecraft:remove_entities", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetEntityDataPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_entity_data"); + return PlayPacketIdHelper.byName("minecraft:set_entity_data", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetTitleTextPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_title_text"); + return PlayPacketIdHelper.byName("minecraft:set_title_text", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetSubtitleTextPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_subtitle_text"); + return PlayPacketIdHelper.byName("minecraft:set_subtitle_text", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetActionBarTextPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_action_bar_text"); + return PlayPacketIdHelper.byName("minecraft:set_action_bar_text", PacketFlow.CLIENTBOUND); } @Override public int clientboundBossEventPacket() { - return PacketIdFinder.clientboundByName("minecraft:boss_event"); + return PlayPacketIdHelper.byName("minecraft:boss_event", PacketFlow.CLIENTBOUND); } @Override public int clientboundSystemChatPacket() { - return PacketIdFinder.clientboundByName("minecraft:system_chat"); + return PlayPacketIdHelper.byName("minecraft:system_chat", PacketFlow.CLIENTBOUND); } @Override public int clientboundTabListPacket() { - return PacketIdFinder.clientboundByName("minecraft:tab_list"); + return PlayPacketIdHelper.byName("minecraft:tab_list", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetPlayerTeamPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_player_team"); + return PlayPacketIdHelper.byName("minecraft:set_player_team", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetObjectivePacket() { - return PacketIdFinder.clientboundByName("minecraft:set_objective"); + return PlayPacketIdHelper.byName("minecraft:set_objective", PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelChunkWithLightPacket() { - return PacketIdFinder.clientboundByName("minecraft:level_chunk_with_light"); + return PlayPacketIdHelper.byName("minecraft:level_chunk_with_light", PacketFlow.CLIENTBOUND); } @Override public int clientboundPlayerInfoUpdatePacket() { - return PacketIdFinder.clientboundByName("minecraft:player_info_update"); + return PlayPacketIdHelper.byName("minecraft:player_info_update", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetScorePacket() { - return PacketIdFinder.clientboundByName("minecraft:set_score"); + return PlayPacketIdHelper.byName("minecraft:set_score", PacketFlow.CLIENTBOUND); } @Override public int clientboundContainerSetContentPacket() { - return PacketIdFinder.clientboundByName("minecraft:container_set_content"); + return PlayPacketIdHelper.byName("minecraft:container_set_content", PacketFlow.CLIENTBOUND); } @Override public int clientboundContainerSetSlotPacket() { - return PacketIdFinder.clientboundByName("minecraft:container_set_slot"); + return PlayPacketIdHelper.byName("minecraft:container_set_slot", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetCursorItemPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_cursor_item"); + return PlayPacketIdHelper.byName("minecraft:set_cursor_item", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetEquipmentPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_equipment"); + return PlayPacketIdHelper.byName("minecraft:set_equipment", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetPlayerInventoryPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_player_inventory"); + return PlayPacketIdHelper.byName("minecraft:set_player_inventory", PacketFlow.CLIENTBOUND); } @Override public int clientboundBlockEventPacket() { - return PacketIdFinder.clientboundByName("minecraft:block_event"); + return PlayPacketIdHelper.byName("minecraft:block_event", PacketFlow.CLIENTBOUND); } @Override public int clientboundRecipeBookAddPacket() { - return PacketIdFinder.clientboundByName("minecraft:recipe_book_add"); + return PlayPacketIdHelper.byName("minecraft:recipe_book_add", PacketFlow.CLIENTBOUND); } @Override public int clientboundPlaceGhostRecipePacket() { - return PacketIdFinder.clientboundByName("minecraft:place_ghost_recipe"); + return PlayPacketIdHelper.byName("minecraft:place_ghost_recipe", PacketFlow.CLIENTBOUND); } @Override public int clientboundUpdateRecipesPacket() { - return PacketIdFinder.clientboundByName("minecraft:update_recipes"); + return PlayPacketIdHelper.byName("minecraft:update_recipes", PacketFlow.CLIENTBOUND); } @Override public int clientboundUpdateAdvancementsPacket() { - return PacketIdFinder.clientboundByName("minecraft:update_advancements"); - } - - @Override - public int serverboundContainerClickPacket() { - return PacketIdFinder.serverboundByName("minecraft:container_click"); - } - - @Override - public int serverboundSetCreativeModeSlotPacket() { - return PacketIdFinder.serverboundByName("minecraft:set_creative_mode_slot"); - } - - @Override - public int serverboundInteractPacket() { - return PacketIdFinder.serverboundByName("minecraft:interact"); + return PlayPacketIdHelper.byName("minecraft:update_advancements", PacketFlow.CLIENTBOUND); } @Override public int clientboundForgetLevelChunkPacket() { - return PacketIdFinder.clientboundByName("minecraft:forget_level_chunk"); + return PlayPacketIdHelper.byName("minecraft:forget_level_chunk", PacketFlow.CLIENTBOUND); + } + + @Override + public int serverboundContainerClickPacket() { + return PlayPacketIdHelper.byName("minecraft:container_click", PacketFlow.SERVERBOUND); + } + + @Override + public int serverboundSetCreativeModeSlotPacket() { + return PlayPacketIdHelper.byName("minecraft:set_creative_mode_slot", PacketFlow.SERVERBOUND); + } + + @Override + public int serverboundInteractPacket() { + return PlayPacketIdHelper.byName("minecraft:interact", PacketFlow.SERVERBOUND); } @Override public int serverboundCustomPayloadPacket() { - return PacketIdFinder.serverboundByName("custom_payload"); + return PlayPacketIdHelper.byName("custom_payload", PacketFlow.SERVERBOUND); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java new file mode 100644 index 000000000..8d903bca8 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java @@ -0,0 +1,61 @@ +package net.momirealms.craftengine.bukkit.plugin.network.id; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.network.PacketFlow; +import net.momirealms.craftengine.core.util.VersionHelper; + +import java.util.*; + +public class PlayPacketIdHelper { + // 1.20.5-latest + private static final Map> byName = new EnumMap<>(PacketFlow.class); + // 1.20-1.20.4 + private static final Map, Integer>> byClazz = new EnumMap<>(PacketFlow.class); + + static { + try { + if (VersionHelper.isOrAbove1_21()) { + Object packetReport = CoreReflections.constructor$PacketReport.newInstance((Object) null); + JsonObject packetReportData = ((JsonElement) CoreReflections.method$PacketReport$serializePackets.invoke(packetReport)).getAsJsonObject(); + JsonObject playData = packetReportData.get("play").getAsJsonObject(); + for (Map.Entry entry : playData.entrySet()) { + Map ids = new HashMap<>(); + byName.put(PacketFlow.valueOf(entry.getKey().toUpperCase(Locale.ROOT)), ids); + for (var entry2 : entry.getValue().getAsJsonObject().entrySet()) { + ids.put(entry2.getKey(), entry2.getValue().getAsJsonObject().get("protocol_id").getAsInt()); + } + } + } else if (VersionHelper.isOrAbove1_20_5()) { + for (Map.Entry> entry : FastNMS.INSTANCE.gamePacketIdsByName().entrySet()) { + byName.put(PacketFlow.valueOf(entry.getKey().toUpperCase(Locale.ROOT)), entry.getValue()); + } + } else { + for (Map.Entry, Integer>> entry : FastNMS.INSTANCE.gamePacketIdsByClazz().entrySet()) { + byClazz.put(PacketFlow.valueOf(entry.getKey().toUpperCase(Locale.ROOT)), entry.getValue()); + } + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to init packet registry", e); + } + } + + public static int count(PacketFlow direction) { + if (VersionHelper.isOrAbove1_20_5()) { + return byName.getOrDefault(direction, Collections.emptyMap()).size(); + } else { + return byClazz.getOrDefault(direction, Collections.emptyMap()).size(); + } + } + + public static int byName(String packetName, PacketFlow direction) { + return byName.get(direction).getOrDefault(packetName, -1); + } + + public static int byClazz(Class clazz, PacketFlow direction) { + return byClazz.get(direction).getOrDefault(clazz, -1); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListener.java new file mode 100644 index 000000000..ebc7dbe34 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListener.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.bukkit.plugin.network.listener; + +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; + +public interface ByteBufferPacketListener { + + default void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + } + + default void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/NMSPacketListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/NMSPacketListener.java new file mode 100644 index 000000000..b7471726b --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/NMSPacketListener.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.bukkit.plugin.network.listener; + +import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; + +public interface NMSPacketListener { + + default void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + } + + default void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java index 808dd56eb..2db50e789 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java @@ -22,6 +22,8 @@ public interface NetworkManager extends Manageable { Channel getChannel(Player player); + int remapBlockState(int stateId, boolean enableMod); + Player[] onlineUsers(); default void sendPacket(@NotNull NetWorkUser player, Object packet) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/PacketFlow.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/PacketFlow.java new file mode 100644 index 000000000..2311d2fad --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/PacketFlow.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.plugin.network; + +public enum PacketFlow { + SERVERBOUND, + CLIENTBOUND; +} diff --git a/gradle.properties b/gradle.properties index 3dfd4ae54..20d23a1d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -60,9 +60,9 @@ authlib_version=6.0.58 concurrent_util_version=0.0.3 # Proxy settings -#systemProp.socks.proxyHost=127.0.0.1 -#systemProp.socks.proxyPort=7890 -#systemProp.http.proxyHost=127.0.0.1 -#systemProp.http.proxyPort=7890 -#systemProp.https.proxyHost=127.0.0.1 -#systemProp.https.proxyPort=7890 \ No newline at end of file +systemProp.socks.proxyHost=127.0.0.1 +systemProp.socks.proxyPort=7890 +systemProp.http.proxyHost=127.0.0.1 +systemProp.http.proxyPort=7890 +systemProp.https.proxyHost=127.0.0.1 +systemProp.https.proxyPort=7890 \ No newline at end of file From 52f2106067100c806ba087928569bbc764fa063d Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <972454774@qq.com> Date: Fri, 19 Sep 2025 00:16:57 +0800 Subject: [PATCH 017/125] =?UTF-8?q?=E6=94=B9=E5=96=84=E7=BD=91=E7=BB=9C?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 101 +++++++++--------- .../plugin/network/id/PlayPacketIdHelper.java | 14 +++ .../ByteBufferPacketListenerHolder.java | 4 + 3 files changed, 69 insertions(+), 50 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListenerHolder.java 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 370b57d79..26bf40917 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 @@ -32,10 +32,11 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor; import net.momirealms.craftengine.bukkit.plugin.network.handler.*; -import net.momirealms.craftengine.bukkit.plugin.network.id.PlayPacketIdHelper; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20_5; +import net.momirealms.craftengine.bukkit.plugin.network.id.PlayPacketIdHelper; import net.momirealms.craftengine.bukkit.plugin.network.listener.ByteBufferPacketListener; +import net.momirealms.craftengine.bukkit.plugin.network.listener.ByteBufferPacketListenerHolder; import net.momirealms.craftengine.bukkit.plugin.network.listener.NMSPacketListener; import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; @@ -114,8 +115,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private final BukkitCraftEngine plugin; private final Map, NMSPacketListener> nmsPacketListeners = new IdentityHashMap<>(128); - private final ByteBufferPacketListener[] s2cGamePacketListeners; - private final ByteBufferPacketListener[] c2sGamePacketListeners; + private final ByteBufferPacketListenerHolder[] s2cGamePacketListeners; + private final ByteBufferPacketListenerHolder[] c2sGamePacketListeners; private final TriConsumer packetConsumer; private final TriConsumer, Object> packetsConsumer; @@ -144,8 +145,8 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @SuppressWarnings("unchecked") public BukkitNetworkManager(BukkitCraftEngine plugin) { instance = this; - this.s2cGamePacketListeners = new ByteBufferPacketListener[PlayPacketIdHelper.count(PacketFlow.CLIENTBOUND)]; - this.c2sGamePacketListeners = new ByteBufferPacketListener[PlayPacketIdHelper.count(PacketFlow.SERVERBOUND)]; + this.s2cGamePacketListeners = new ByteBufferPacketListenerHolder[PlayPacketIdHelper.count(PacketFlow.CLIENTBOUND)]; + this.c2sGamePacketListeners = new ByteBufferPacketListenerHolder[PlayPacketIdHelper.count(PacketFlow.SERVERBOUND)]; this.hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; this.hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; this.plugin = plugin; @@ -213,20 +214,20 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes this.nmsPacketListeners.put(packet, listener); } - private void registerS2CGamePacketListener(final ByteBufferPacketListener function, int id) { + private void registerS2CGamePacketListener(final ByteBufferPacketListener listener, int id, String name) { if (id == -1) return; if (id < 0 || id >= this.s2cGamePacketListeners.length) { throw new IllegalArgumentException("Invalid packet id: " + id); } - this.s2cGamePacketListeners[id] = function; + this.s2cGamePacketListeners[id] = new ByteBufferPacketListenerHolder(name, listener); } - private void registerC2SGamePacketListener(final ByteBufferPacketListener function, int id) { + private void registerC2SGamePacketListener(final ByteBufferPacketListener listener, int id, String name) { if (id == -1) return; if (id < 0 || id >= this.c2sGamePacketListeners.length) { throw new IllegalArgumentException("Invalid packet id: " + id); } - this.c2sGamePacketListeners[id] = function; + this.c2sGamePacketListeners[id] = new ByteBufferPacketListenerHolder(name, listener); } public void addFakePlayer(Player player) { @@ -281,18 +282,18 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } this.blockStateRemapper = newMappings; this.modBlockStateRemapper = newMappingsMOD; - registerS2CGamePacketListener(new LevelChunkWithLightListener(newMappings, newMappingsMOD, registrySize, RegistryUtils.currentBiomeRegistrySize()), this.packetIds.clientboundLevelChunkWithLightPacket()); - registerS2CGamePacketListener(new SectionBlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundSectionBlocksUpdatePacket()); - registerS2CGamePacketListener(new BlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundBlockUpdatePacket()); + registerS2CGamePacketListener(new LevelChunkWithLightListener(newMappings, newMappingsMOD, registrySize, RegistryUtils.currentBiomeRegistrySize()), this.packetIds.clientboundLevelChunkWithLightPacket(), "ClientboundLevelChunkWithLightPacket"); + registerS2CGamePacketListener(new SectionBlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundSectionBlocksUpdatePacket(), "ClientboundSectionBlocksUpdatePacket"); + registerS2CGamePacketListener(new BlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundBlockUpdatePacket(), "ClientboundBlockUpdatePacket"); registerS2CGamePacketListener( VersionHelper.isOrAbove1_21_4() ? new LevelParticleListener1_21_4(newMappings, newMappingsMOD) : (VersionHelper.isOrAbove1_20_5() ? new LevelParticleListener1_20_5(newMappings, newMappingsMOD) : new LevelParticleListener1_20(newMappings, newMappingsMOD)), - this.packetIds.clientboundLevelParticlesPacket() + this.packetIds.clientboundLevelParticlesPacket(), "ClientboundLevelParticlesPacket" ); - registerS2CGamePacketListener(new LevelEventListener(newMappings, newMappingsMOD), this.packetIds.clientboundLevelEventPacket()); + registerS2CGamePacketListener(new LevelEventListener(newMappings, newMappingsMOD), this.packetIds.clientboundLevelEventPacket(), "ClientboundLevelEventPacket"); } private void registerPacketListeners() { @@ -321,78 +322,78 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerNMSPacketConsumer(new LoginFinishedListener(), NetworkReflections.clazz$ClientboundLoginFinishedPacket); registerNMSPacketConsumer(new UpdateTagsListener(), NetworkReflections.clazz$ClientboundUpdateTagsPacket); registerNMSPacketConsumer(new ContainerClickListener1_21_5(), VersionHelper.isOrAbove1_21_5() ? NetworkReflections.clazz$ServerboundContainerClickPacket : null); - registerS2CGamePacketListener(new ForgetLevelChunkListener(), this.packetIds.clientboundForgetLevelChunkPacket()); - registerS2CGamePacketListener(new SetScoreListener1_20_3(), VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1); - registerS2CGamePacketListener(new AddRecipeBookListener(), this.packetIds.clientboundRecipeBookAddPacket()); - registerS2CGamePacketListener(new PlaceGhostRecipeListener(), this.packetIds.clientboundPlaceGhostRecipePacket()); - registerS2CGamePacketListener(new UpdateRecipesListener(), this.packetIds.clientboundUpdateRecipesPacket()); - registerS2CGamePacketListener(new UpdateAdvancementsListener(), this.packetIds.clientboundUpdateAdvancementsPacket()); - registerS2CGamePacketListener(new RemoveEntityListener(), this.packetIds.clientboundRemoveEntitiesPacket()); - registerS2CGamePacketListener(new SoundListener(), this.packetIds.clientboundSoundPacket()); - registerS2CGamePacketListener(new ContainerSetContentListener(), this.packetIds.clientboundContainerSetContentPacket()); - registerS2CGamePacketListener(new ContainerSetSlotListener(), this.packetIds.clientboundContainerSetSlotPacket()); - registerS2CGamePacketListener(new SetCursorItemListener(), this.packetIds.clientboundSetCursorItemPacket()); - registerS2CGamePacketListener(new SetEquipmentListener(), this.packetIds.clientboundSetEquipmentPacket()); - registerS2CGamePacketListener(new SetPlayerInventoryListener1_21_2(), VersionHelper.isOrAbove1_21_2() ? this.packetIds.clientboundSetPlayerInventoryPacket() : -1); - registerS2CGamePacketListener(new SetEntityDataListener(), this.packetIds.clientboundSetEntityDataPacket()); - registerC2SGamePacketListener(new SetCreativeModeSlotListener(), this.packetIds.serverboundSetCreativeModeSlotPacket()); - registerC2SGamePacketListener(new ContainerClick1_20(), VersionHelper.isOrAbove1_21_5() ? -1 : this.packetIds.serverboundContainerClickPacket()); - registerC2SGamePacketListener(new InteractEntityListener(), this.packetIds.serverboundInteractPacket()); - registerC2SGamePacketListener(new CustomPayloadListener1_20(), VersionHelper.isOrAbove1_20_2() ? -1 : this.packetIds.serverboundCustomPayloadPacket()); - registerS2CGamePacketListener(new AddEntityListener(RegistryUtils.currentEntityTypeRegistrySize()), this.packetIds.clientboundAddEntityPacket()); + registerS2CGamePacketListener(new ForgetLevelChunkListener(), this.packetIds.clientboundForgetLevelChunkPacket(), "ClientboundForgetLevelChunkPacket"); + registerS2CGamePacketListener(new SetScoreListener1_20_3(), VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1, "ClientboundSetScorePacket"); + registerS2CGamePacketListener(new AddRecipeBookListener(), this.packetIds.clientboundRecipeBookAddPacket(), "ClientboundRecipeBookAddPacket"); + registerS2CGamePacketListener(new PlaceGhostRecipeListener(), this.packetIds.clientboundPlaceGhostRecipePacket(), "ClientboundPlaceGhostRecipePacket"); + registerS2CGamePacketListener(new UpdateRecipesListener(), this.packetIds.clientboundUpdateRecipesPacket(), "ClientboundUpdateRecipesPacket"); + registerS2CGamePacketListener(new UpdateAdvancementsListener(), this.packetIds.clientboundUpdateAdvancementsPacket(), "ClientboundUpdateAdvancementsPacket"); + registerS2CGamePacketListener(new RemoveEntityListener(), this.packetIds.clientboundRemoveEntitiesPacket(), "ClientboundRemoveEntitiesPacket"); + registerS2CGamePacketListener(new SoundListener(), this.packetIds.clientboundSoundPacket(), "ClientboundSoundPacket"); + registerS2CGamePacketListener(new ContainerSetContentListener(), this.packetIds.clientboundContainerSetContentPacket(), "ClientboundContainerSetContentPacket"); + registerS2CGamePacketListener(new ContainerSetSlotListener(), this.packetIds.clientboundContainerSetSlotPacket(), "ClientboundContainerSetSlotPacket"); + registerS2CGamePacketListener(new SetCursorItemListener(), this.packetIds.clientboundSetCursorItemPacket(), "ClientboundSetCursorItemPacket"); + registerS2CGamePacketListener(new SetEquipmentListener(), this.packetIds.clientboundSetEquipmentPacket(), "ClientboundSetEquipmentPacket"); + registerS2CGamePacketListener(new SetPlayerInventoryListener1_21_2(), VersionHelper.isOrAbove1_21_2() ? this.packetIds.clientboundSetPlayerInventoryPacket() : -1, "ClientboundSetPlayerInventoryPacket"); + registerS2CGamePacketListener(new SetEntityDataListener(), this.packetIds.clientboundSetEntityDataPacket(), "ClientboundSetEntityDataPacket"); + registerC2SGamePacketListener(new SetCreativeModeSlotListener(), this.packetIds.serverboundSetCreativeModeSlotPacket(), "ServerboundSetCreativeModeSlotPacket"); + registerC2SGamePacketListener(new ContainerClick1_20(), VersionHelper.isOrAbove1_21_5() ? -1 : this.packetIds.serverboundContainerClickPacket(), "ServerboundContainerClickPacket"); + registerC2SGamePacketListener(new InteractEntityListener(), this.packetIds.serverboundInteractPacket(), "ServerboundInteractPacket"); + registerC2SGamePacketListener(new CustomPayloadListener1_20(), VersionHelper.isOrAbove1_20_2() ? -1 : this.packetIds.serverboundCustomPayloadPacket(), "ServerboundCustomPayloadPacket"); + registerS2CGamePacketListener(new AddEntityListener(RegistryUtils.currentEntityTypeRegistrySize()), this.packetIds.clientboundAddEntityPacket(), "ClientboundAddEntityPacket"); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? new OpenScreenListener1_20_3() : new OpenScreenListener1_20(), - this.packetIds.clientboundOpenScreenPacket() + this.packetIds.clientboundOpenScreenPacket(), "ClientboundOpenScreenPacket" ); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? new SystemChatListener1_20_3() : new SystemChatListener1_20(), - this.packetIds.clientboundSystemChatPacket() + this.packetIds.clientboundSystemChatPacket(), "ClientboundSystemChatPacket" ); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? new SetActionBarListener1_20_3() : new SetActionBarListener1_20(), - this.packetIds.clientboundSetActionBarTextPacket() + this.packetIds.clientboundSetActionBarTextPacket(), "ClientboundSetActionBarTextPacket" ); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? new TabListListener1_20_3() : new TabListListener1_20(), - this.packetIds.clientboundTabListPacket() + this.packetIds.clientboundTabListPacket(), "ClientboundTabListPacket" ); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? new SetTitleListener1_20_3() : new SetTitleListener1_20(), - this.packetIds.clientboundSetTitleTextPacket() + this.packetIds.clientboundSetTitleTextPacket(), "ClientboundSetTitleTextPacket" ); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? new SetSubtitleListener1_20_3() : new SetSubtitleListener1_20(), - this.packetIds.clientboundSetSubtitleTextPacket() + this.packetIds.clientboundSetSubtitleTextPacket(), "ClientboundSetSubtitleTextPacket" ); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? new BossEventListener1_20_3() : new BossEventListener1_20(), - this.packetIds.clientboundBossEventPacket() + this.packetIds.clientboundBossEventPacket(), "ClientboundBossEventPacket" ); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? new TeamListener1_20_3() : new TeamListener1_20(), - this.packetIds.clientboundSetPlayerTeamPacket() + this.packetIds.clientboundSetPlayerTeamPacket(), "ClientboundSetPlayerTeamPacket" ); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? new SetObjectiveListener1_20_3() : new SetObjectiveListener1_20(), - this.packetIds.clientboundSetObjectivePacket() + this.packetIds.clientboundSetObjectivePacket(), "ClientboundSetObjectivePacket" ); } @@ -894,24 +895,24 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes protected void handleS2CByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - ByteBufferPacketListener s2cGamePacketListener = this.s2cGamePacketListeners[packetID]; - if (s2cGamePacketListener != null) { + ByteBufferPacketListenerHolder holder = this.s2cGamePacketListeners[packetID]; + if (holder != null) { try { - s2cGamePacketListener.onPacketSend(user, event); + holder.listener().onPacketSend(user, event); } catch (Throwable t) { - this.plugin.logger().warn("An error occurred when handling sent packet id: " + packetID, t); + this.plugin.logger().warn("An error occurred when handling packet " + holder.id(), t); } } } protected void handleC2SByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - ByteBufferPacketListener c2sGamePacketListener = this.c2sGamePacketListeners[packetID]; - if (c2sGamePacketListener != null) { + ByteBufferPacketListenerHolder holder = this.c2sGamePacketListeners[packetID]; + if (holder != null) { try { - c2sGamePacketListener.onPacketReceive(user, event); + holder.listener().onPacketReceive(user, event); } catch (Throwable t) { - this.plugin.logger().warn("An error occurred when handling received packet id: " + packetID, t); + this.plugin.logger().warn("An error occurred when handling packet " + holder.id(), t); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java index 8d903bca8..19ac2a8d1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java @@ -13,6 +13,7 @@ import java.util.*; public class PlayPacketIdHelper { // 1.20.5-latest private static final Map> byName = new EnumMap<>(PacketFlow.class); + private static final Map byId = new EnumMap<>(PacketFlow.class); // 1.20-1.20.4 private static final Map, Integer>> byClazz = new EnumMap<>(PacketFlow.class); @@ -38,6 +39,15 @@ public class PlayPacketIdHelper { byClazz.put(PacketFlow.valueOf(entry.getKey().toUpperCase(Locale.ROOT)), entry.getValue()); } } + if (!byName.isEmpty()) { + for (Map.Entry> entry : byName.entrySet()) { + String[] ids = new String[entry.getValue().size()]; + for (Map.Entry nameIdEntry : entry.getValue().entrySet()) { + ids[nameIdEntry.getValue()] = nameIdEntry.getKey(); + } + byId.put(entry.getKey(), ids); + } + } } catch (Exception e) { CraftEngine.instance().logger().warn("Failed to init packet registry", e); } @@ -51,6 +61,10 @@ public class PlayPacketIdHelper { } } + public static String byId(int id, PacketFlow direction) { + return byId.get(direction)[id]; + } + public static int byName(String packetName, PacketFlow direction) { return byName.get(direction).getOrDefault(packetName, -1); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListenerHolder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListenerHolder.java new file mode 100644 index 000000000..d59614303 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListenerHolder.java @@ -0,0 +1,4 @@ +package net.momirealms.craftengine.bukkit.plugin.network.listener; + +public record ByteBufferPacketListenerHolder(String id, ByteBufferPacketListener listener) { +} From 80a021d197a9344373ca1fcf75c5da02f658e3d0 Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <972454774@qq.com> Date: Fri, 19 Sep 2025 00:32:13 +0800 Subject: [PATCH 018/125] =?UTF-8?q?=E7=A7=BB=E9=99=A4viaversion=E5=88=A4?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 14 +++----------- gradle.properties | 2 +- 2 files changed, 4 insertions(+), 12 deletions(-) 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 26bf40917..2952fe1bc 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 @@ -137,7 +137,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static final String PACKET_DECODER = "craftengine_decoder"; private final boolean hasModelEngine; - private final boolean hasViaVersion; private int[] blockStateRemapper; private int[] modBlockStateRemapper; @@ -148,7 +147,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes this.s2cGamePacketListeners = new ByteBufferPacketListenerHolder[PlayPacketIdHelper.count(PacketFlow.CLIENTBOUND)]; this.c2sGamePacketListeners = new ByteBufferPacketListenerHolder[PlayPacketIdHelper.count(PacketFlow.SERVERBOUND)]; this.hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; - this.hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; this.plugin = plugin; // set up packet id this.packetIds = VersionHelper.isOrAbove1_20_5() ? new PacketIds1_20_5() : new PacketIds1_20(); @@ -534,13 +532,9 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes return hasModelEngine; } - public boolean hasViaVersion() { - return hasViaVersion; - } - public void simulatePacket(@NotNull NetWorkUser player, Object packet) { Channel channel = player.nettyChannel(); - if (channel.isOpen()) { + if (channel != null && channel.isOpen()) { List handlerNames = channel.pipeline().names(); if (handlerNames.contains("via-encoder")) { channel.pipeline().context("via-decoder").fireChannelRead(packet); @@ -673,9 +667,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes String encoderName = pipeline.names().contains("outbound_config") ? "outbound_config" : "encoder"; pipeline.addBefore(encoderName, PACKET_ENCODER, new PluginChannelEncoder(user)); - channel.closeFuture().addListener((ChannelFutureListener) future -> { - handleDisconnection(user.nettyChannel()); - }); + channel.closeFuture().addListener((ChannelFutureListener) future -> handleDisconnection(user.nettyChannel())); setUser(channel, user); } @@ -933,7 +925,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private void decompress(ChannelHandlerContext ctx, ByteBuf input, ByteBuf output) { ChannelHandler decompressor = ctx.pipeline().get("decompress"); if (decompressor != null) { - ByteBuf temp = (ByteBuf) callDecode(decompressor, ctx, input).get(0); + ByteBuf temp = (ByteBuf) callDecode(decompressor, ctx, input).getFirst(); try { output.clear().writeBytes(temp); } finally { diff --git a/gradle.properties b/gradle.properties index 20d23a1d9..efd0b34c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.2 +project_version=0.0.63.3 config_version=45 lang_version=29 project_group=net.momirealms From d1541d428fd4f8eebb090c82a3b1f0fc0cefb686 Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <972454774@qq.com> Date: Fri, 19 Sep 2025 00:46:50 +0800 Subject: [PATCH 019/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=87=8D=E8=BD=BD?= =?UTF-8?q?=E5=90=8E=E5=9F=BA=E4=BA=8Etag=E7=9A=84=E7=89=A9=E5=93=81?= =?UTF-8?q?=E6=9C=AA=E8=83=BD=E5=8F=8A=E6=97=B6=E5=8F=82=E4=B8=8E=E9=85=8D?= =?UTF-8?q?=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/recipe/BukkitRecipeManager.java | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) 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 b738734a3..06d11bf38 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 @@ -258,7 +258,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { // 已经被替换过的数据包配方 private final Set replacedDatapackRecipes = new HashSet<>(); // 换成的数据包配方 - private Map> lastDatapackRecipes = Map.of(); + private Map lastDatapackRecipes = Map.of(); private Object lastRecipeManager = null; public BukkitRecipeManager(BukkitCraftEngine plugin) { @@ -386,18 +386,33 @@ public class BukkitRecipeManager extends AbstractRecipeManager { } boolean hasDisabledAny = !Config.disabledVanillaRecipes().isEmpty(); - for (Map.Entry> entry : this.lastDatapackRecipes.entrySet()) { + for (Map.Entry entry : this.lastDatapackRecipes.entrySet()) { + Key id = entry.getKey(); if (hasDisabledAny && Config.disabledVanillaRecipes().contains(entry.getKey())) { - this.recipesToUnregister.add(Pair.of(entry.getKey(), false)); + this.recipesToUnregister.add(Pair.of(id, false)); continue; } - markAsDataPackRecipe(entry.getKey()); - registerInternalRecipe(entry.getKey(), entry.getValue()); + + JsonObject jsonObject = entry.getValue(); + Key serializerType = Key.of(jsonObject.get("type").getAsString()); + // noinspection unchecked + RecipeSerializer> serializer = (RecipeSerializer>) BuiltInRegistries.RECIPE_SERIALIZER.getValue(serializerType); + if (serializer == null) { + continue; + } + + try { + Recipe recipe = serializer.readJson(id, jsonObject); + markAsDataPackRecipe(id); + registerInternalRecipe(id, recipe); + } catch (Exception e) { + this.plugin.logger().warn("Failed to load data pack recipe " + id + ". Json: " + jsonObject, e); + } } } @SuppressWarnings("unchecked") - private Map> scanResources() throws Throwable { + private Map scanResources() throws Throwable { Object fileToIdConverter = CoreReflections.methodHandle$FileToIdConverter$json.invokeExact((String) (VersionHelper.isOrAbove1_21() ? "recipe" : "recipes")); Object minecraftServer = FastNMS.INSTANCE.method$MinecraftServer$getServer(); Object packRepository = CoreReflections.methodHandle$MinecraftServer$getPackRepository.invokeExact(minecraftServer); @@ -406,7 +421,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { for (Object pack : selected) { packResources.add(CoreReflections.methodHandle$Pack$open.invokeExact(pack)); } - Map> recipes = new HashMap<>(); + Map recipes = new HashMap<>(); try (AutoCloseable resourceManager = (AutoCloseable) CoreReflections.methodHandle$MultiPackResourceManagerConstructor.invokeExact(CoreReflections.instance$PackType$SERVER_DATA, packResources)) { Map scannedResources = (Map) CoreReflections.methodHandle$FileToIdConverter$listMatchingResources.invokeExact(fileToIdConverter, resourceManager); @@ -414,17 +429,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { Key id = extractKeyFromResourceLocation(entry.getKey().toString()); Reader reader = (Reader) CoreReflections.methodHandle$Resource$openAsReader.invokeExact(entry.getValue()); JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); - Key serializerType = Key.of(jsonObject.get("type").getAsString()); - RecipeSerializer> serializer = (RecipeSerializer>) BuiltInRegistries.RECIPE_SERIALIZER.getValue(serializerType); - if (serializer == null) { - continue; - } - try { - Recipe recipe = serializer.readJson(id, jsonObject); - recipes.put(id, recipe); - } catch (Exception e) { - this.plugin.logger().warn("Failed to load data pack recipe " + id + ". Json: " + jsonObject, e); - } + recipes.put(id, jsonObject); } } catch (Throwable e) { this.plugin.logger().warn("Unknown error occurred when loading data pack recipes", e); From 517965711b6f409d1ee18fa08a44dde2e98317fa Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <972454774@qq.com> Date: Fri, 19 Sep 2025 00:59:17 +0800 Subject: [PATCH 020/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0stepOn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/injector/BlockGenerator.java | 17 +++++++++++++++++ .../reflection/minecraft/CoreReflections.java | 4 ++++ .../craftengine/core/block/BlockBehavior.java | 5 +++++ 3 files changed, 26 insertions(+) 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 f7105c15e..ae5e8c670 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 @@ -167,6 +167,9 @@ public final class BlockGenerator { // updateEntityMovementAfterFallOn .method(ElementMatchers.is(CoreReflections.method$Block$updateEntityMovementAfterFallOn)) .intercept(MethodDelegation.to(UpdateEntityMovementAfterFallOnInterceptor.INSTANCE)) + // stepOn + .method(ElementMatchers.is(CoreReflections.method$Block$stepOn)) + .intercept(MethodDelegation.to(StepOnInterceptor.INSTANCE)) ; // 1.21.5+ if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) { @@ -708,6 +711,20 @@ public final class BlockGenerator { } } + public static class StepOnInterceptor { + public static final StepOnInterceptor INSTANCE = new StepOnInterceptor(); + + @RuntimeType + public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + holder.value().stepOn(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run stepOn", e); + } + } + } + public static class FallOnInterceptor { public static final FallOnInterceptor INSTANCE = new FallOnInterceptor(); 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 48eb0072e..30a9f19cc 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 @@ -1687,6 +1687,10 @@ public final class CoreReflections { ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, clazz$BlockState, clazz$LevelReader, clazz$BlockPos) ); + public static final Method method$Block$stepOn = requireNonNull( + ReflectionUtils.getMethod(clazz$Block, void.class, new String[] {"stepOn", "a"}, clazz$Level, clazz$BlockPos, clazz$BlockState, clazz$Entity) + ); + public static final Method method$BlockBehaviour$onExplosionHit = MiscUtils.requireNonNullIf( ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, clazz$BlockState, VersionHelper.isOrAbove1_21_2() ? clazz$ServerLevel : clazz$Level, clazz$BlockPos, clazz$Explosion, BiConsumer.class), VersionHelper.isOrAbove1_21() 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 4f20228e3..f1aba39ce 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 @@ -178,6 +178,11 @@ public abstract class BlockBehavior { public void spawnAfterBreak(Object thisBlock, Object[] args, Callable superMethod) throws Exception { } + // Level level, BlockPos pos, BlockState state, Entity entity + public void stepOn(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + superMethod.call(); + } + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; } From 2b4ec32d13382f9ca751bbdb8b22ec85ec950d7b Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 19 Sep 2025 01:26:24 +0800 Subject: [PATCH 021/125] =?UTF-8?q?=E6=94=B9=E5=90=8D=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/FenceBlockBehavior.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java index d167464d2..812fcd935 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java @@ -33,7 +33,7 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { private final BooleanProperty eastProperty; private final BooleanProperty southProperty; private final BooleanProperty westProperty; - private final Object selfBlockTag; + private final Object fenceBlockTag; private final Object connectableBlockTag; private final boolean canLeash; @@ -42,7 +42,7 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { BooleanProperty eastProperty, BooleanProperty southProperty, BooleanProperty westProperty, - Object selfBlockTag, + Object fenceBlockTag, Object connectableBlockTag, boolean canLeash) { super(customBlock); @@ -50,7 +50,7 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { this.eastProperty = eastProperty; this.southProperty = southProperty; this.westProperty = westProperty; - this.selfBlockTag = selfBlockTag; + this.fenceBlockTag = fenceBlockTag; this.connectableBlockTag = connectableBlockTag; this.canLeash = canLeash; } @@ -70,7 +70,7 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { private boolean isSameFence(BlockStateWrapper state) { Object blockState = state.literalObject(); - return FastNMS.INSTANCE.method$BlockStateBase$is(blockState, this.selfBlockTag) + return FastNMS.INSTANCE.method$BlockStateBase$is(blockState, this.fenceBlockTag) && FastNMS.INSTANCE.method$BlockStateBase$is(blockState, this.connectableBlockTag) == FastNMS.INSTANCE.method$BlockStateBase$is(this.customBlock.defaultState().customBlockState().literalObject(), this.connectableBlockTag); } @@ -144,12 +144,12 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { BooleanProperty east = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("east"), "warning.config.block.behavior.fence.missing_east"); BooleanProperty south = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("south"), "warning.config.block.behavior.fence.missing_south"); BooleanProperty west = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("west"), "warning.config.block.behavior.fence.missing_west"); - Object selfBlockTag = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("self-block-tag", "minecraft:fences").toString()))); - selfBlockTag = selfBlockTag != null ? selfBlockTag : MTagKeys.Block$FENCES; + Object fenceBlockTag = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("fence-block-tag", "minecraft:fences").toString()))); + fenceBlockTag = fenceBlockTag != null ? fenceBlockTag : MTagKeys.Block$FENCES; Object connectableBlockTag = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("connectable-block-tag", "minecraft:wooden_fences").toString()))); connectableBlockTag = connectableBlockTag != null ? connectableBlockTag : MTagKeys.Block$WOODEN_FENCES; boolean canLeash = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-leash", false), "can-leash"); - return new FenceBlockBehavior(block, north, east, south, west, selfBlockTag, connectableBlockTag, canLeash); + return new FenceBlockBehavior(block, north, east, south, west, fenceBlockTag, connectableBlockTag, canLeash); } } } From 5f54171ec35b1c98bb667905f8761d07e4031219 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 19 Sep 2025 01:37:32 +0800 Subject: [PATCH 022/125] =?UTF-8?q?=E7=AE=80=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/FenceBlockBehavior.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java index 812fcd935..0a4de1cbf 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java @@ -33,7 +33,6 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { private final BooleanProperty eastProperty; private final BooleanProperty southProperty; private final BooleanProperty westProperty; - private final Object fenceBlockTag; private final Object connectableBlockTag; private final boolean canLeash; @@ -42,7 +41,6 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { BooleanProperty eastProperty, BooleanProperty southProperty, BooleanProperty westProperty, - Object fenceBlockTag, Object connectableBlockTag, boolean canLeash) { super(customBlock); @@ -50,7 +48,6 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { this.eastProperty = eastProperty; this.southProperty = southProperty; this.westProperty = westProperty; - this.fenceBlockTag = fenceBlockTag; this.connectableBlockTag = connectableBlockTag; this.canLeash = canLeash; } @@ -70,7 +67,7 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { private boolean isSameFence(BlockStateWrapper state) { Object blockState = state.literalObject(); - return FastNMS.INSTANCE.method$BlockStateBase$is(blockState, this.fenceBlockTag) + return FastNMS.INSTANCE.method$BlockStateBase$is(blockState, MTagKeys.Block$FENCES) && FastNMS.INSTANCE.method$BlockStateBase$is(blockState, this.connectableBlockTag) == FastNMS.INSTANCE.method$BlockStateBase$is(this.customBlock.defaultState().customBlockState().literalObject(), this.connectableBlockTag); } @@ -144,12 +141,10 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { BooleanProperty east = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("east"), "warning.config.block.behavior.fence.missing_east"); BooleanProperty south = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("south"), "warning.config.block.behavior.fence.missing_south"); BooleanProperty west = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("west"), "warning.config.block.behavior.fence.missing_west"); - Object fenceBlockTag = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("fence-block-tag", "minecraft:fences").toString()))); - fenceBlockTag = fenceBlockTag != null ? fenceBlockTag : MTagKeys.Block$FENCES; Object connectableBlockTag = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("connectable-block-tag", "minecraft:wooden_fences").toString()))); connectableBlockTag = connectableBlockTag != null ? connectableBlockTag : MTagKeys.Block$WOODEN_FENCES; boolean canLeash = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-leash", false), "can-leash"); - return new FenceBlockBehavior(block, north, east, south, west, fenceBlockTag, connectableBlockTag, canLeash); + return new FenceBlockBehavior(block, north, east, south, west, connectableBlockTag, canLeash); } } } From 13bcf6333c066bf0d5b4e280275d6865676e3df1 Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <972454774@qq.com> Date: Fri, 19 Sep 2025 01:42:22 +0800 Subject: [PATCH 023/125] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E9=94=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++---- .../block/behavior/DirectionalAttachedBlockBehavior.java | 4 ++-- common-files/src/main/resources/translations/en.yml | 2 +- common-files/src/main/resources/translations/zh_cn.yml | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 836dcd8f0..daf38199a 100644 --- a/README.md +++ b/README.md @@ -54,10 +54,10 @@ The code you contribute will be open-sourced under the GPLv3 license. If you pre 3. Once done, submit a **pull request** to **dev** branch for review. We appreciate your contributions! ## Differences Between Versions -| Version | Official Support | Max Players | Dev Builds | -|-------------------|------------------|-------------|------------| -| Community Edition | ❌ No | 30 | ❌ No | -| Premium Edition | ✔️ Yes | Unlimited | ✔️ Yes | +| Version | Official Support | Exclusive Features | Dev Builds | +|-------------------|------------------|--------------------|------------| +| Community Edition | ❌ No | ❌ No | ❌ No | +| Premium Edition | ✔️ Yes | ✔️ Yes | ✔️ Yes | ### 💖 Support the Developer Help sustain CraftEngine's development by going Premium! diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java index 1b33c2747..a155235db 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java @@ -137,11 +137,11 @@ public class DirectionalAttachedBlockBehavior extends AbstractCanSurviveBlockBeh @Override public BlockBehavior create(CustomBlock block, Map arguments) { - Property facing = ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.surface_attached.missing_facing"); + Property facing = ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.directional_attached.missing_facing"); boolean isHorizontalDirection = facing.valueClass() == HorizontalDirection.class; boolean isDirection = facing.valueClass() == Direction.class; if (!(isHorizontalDirection || isDirection)) { - throw new LocalizedResourceConfigException("warning.config.block.behavior.surface_attached.missing_facing"); + throw new LocalizedResourceConfigException("warning.config.block.behavior.directional_attached.missing_facing"); } Tuple, Set, Set> tuple = readTagsAndState(arguments); int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 559efd97f..71250f8c3 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -319,7 +319,7 @@ warning.config.block.behavior.pressure_plate.missing_powered: "Issue fou 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_high.missing_half: "Issue found in file - The block '' is missing the required 'half' property for 'double_block' behavior." warning.config.block.behavior.change_over_time.missing_next_block: "Issue found in file - The block '' is missing the required 'next_block' argument for 'change_over_time_block' behavior." -warning.config.block.behavior.surface_attached.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'surface_attached_block' behavior." +warning.config.block.behavior.directional_attached.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'directional_attached_block' behavior." warning.config.block.behavior.wall_torch_particle.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'wall_torch_particle_block' behavior." warning.config.block.behavior.fence.missing_north: "Issue found in file - The block '' is missing the required 'north' property for 'fence_block' behavior." warning.config.block.behavior.fence.missing_east: "Issue found in file - The block '' is missing the required 'east' property for 'fence_block' behavior." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index d15fae40a..1c2c4ca57 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -313,7 +313,7 @@ warning.config.block.behavior.pressure_plate.missing_powered: "在文件 warning.config.block.behavior.grass.missing_feature: "在文件 发现问题 - 方块 '' 的 'grass_block' 行为缺少必需的 'feature' 参数" warning.config.block.behavior.double_high.missing_half: "在文件 发现问题 - 方块 '' 的 'double_block' 行为缺少必需的 'half' 属性" warning.config.block.behavior.change_over_time.missing_next_block: "在文件 发现问题 - 方块 '' 的 'change_over_time_block' 行为缺少必需的 'next-block' 参数" -warning.config.block.behavior.surface_attached.missing_facing: "在文件 发现问题 - 方块 '' 的 'surface_attached_block' 行为缺少必需的 'facing' 属性" +warning.config.block.behavior.directional_attached.missing_facing: "在文件 发现问题 - 方块 '' 的 'directional_attached_block' 行为缺少必需的 'facing' 属性" warning.config.block.behavior.wall_torch_particle.missing_facing: "在文件 发现问题 - 配置项 '' 的 'wall_torch_particle_block' 行为缺少必需的 'facing' 属性" warning.config.block.behavior.fence.missing_north: "在文件 发现问题 - 方块 '' 的 'fence_block' 行为缺少必需的 'north' 属性" warning.config.block.behavior.fence.missing_east: "在文件 发现问题 - 方块 '' 的 'fence_block' 行为缺少必需的 'east' 属性" From a32e50c4b8101a32e7947c2c61e5618fb2e84b37 Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <972454774@qq.com> Date: Fri, 19 Sep 2025 03:19:11 +0800 Subject: [PATCH 024/125] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=8C=BA=E5=9F=9F=E4=BD=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/config.yml | 39 ++++---- .../core/plugin/config/Config.java | 91 ++++++++++--------- 2 files changed, 67 insertions(+), 63 deletions(-) diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index cb1226ba1..c69bf57ba 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -219,24 +219,7 @@ image: chat: true command: true sign: true - # Allow and tags in third-party plugins via packet manipulation - # ⚠️ Disable unused handlers to reduce async thread workload - intercept-packets: - system-chat: true - tab-list: true # Tab list header and footer - player-info: true # Player list in tab - set-score: true - actionbar: true - title: true - bossbar: true - container: true # GUI - team: true # Team prefix, suffix and display name - scoreboard: true - entity-name: false - 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 @@ -287,6 +270,26 @@ image: 128: '\uf844' 256: '\uf845' +network: + # Allow tags in third-party plugins via packet manipulation + # ⚠️ Disable unused handlers to reduce async thread workload + intercept-packets: + system-chat: true + tab-list: true # Tab list header and footer + player-info: true # Player list in tab + set-score: true + actionbar: true + title: true + bossbar: true + container: true # GUI + team: true # Team prefix, suffix and display name + scoreboard: true + entity-name: false + armor-stand: true # Legacy Holograms + text-display: true # Modern Holograms + item: true + advancement: true + recipe: # Master switch for custom recipes # NOTE: When enabled, plugin recipes will OVERRIDE vanilla recipes 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 ffdc1cacf..834947120 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 @@ -134,21 +134,21 @@ public class Config { protected boolean image$illegal_characters_filter$anvil; protected boolean image$illegal_characters_filter$sign; protected boolean image$illegal_characters_filter$book; - protected boolean image$intercept_packets$system_chat; - protected boolean image$intercept_packets$tab_list; - protected boolean image$intercept_packets$actionbar; - protected boolean image$intercept_packets$title; - protected boolean image$intercept_packets$bossbar; - protected boolean image$intercept_packets$container; - protected boolean image$intercept_packets$team; - protected boolean image$intercept_packets$scoreboard; - protected boolean image$intercept_packets$entity_name; - protected boolean image$intercept_packets$text_display; - protected boolean image$intercept_packets$armor_stand; - 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 network$intercept_packets$system_chat; + protected boolean network$intercept_packets$tab_list; + protected boolean network$intercept_packets$actionbar; + protected boolean network$intercept_packets$title; + protected boolean network$intercept_packets$bossbar; + protected boolean network$intercept_packets$container; + protected boolean network$intercept_packets$team; + protected boolean network$intercept_packets$scoreboard; + protected boolean network$intercept_packets$entity_name; + protected boolean network$intercept_packets$text_display; + protected boolean network$intercept_packets$armor_stand; + protected boolean network$intercept_packets$player_info; + protected boolean network$intercept_packets$set_score; + protected boolean network$intercept_packets$item; + protected boolean network$intercept_packets$advancement; protected boolean item$client_bound_model; protected boolean item$non_italic_tag; @@ -405,21 +405,22 @@ public class Config { image$illegal_characters_filter$chat = config.getBoolean("image.illegal-characters-filter.chat", true); image$illegal_characters_filter$command = config.getBoolean("image.illegal-characters-filter.command", true); image$illegal_characters_filter$sign = config.getBoolean("image.illegal-characters-filter.sign", true); - image$intercept_packets$system_chat = config.getBoolean("image.intercept-packets.system-chat", true); - image$intercept_packets$tab_list = config.getBoolean("image.intercept-packets.tab-list", true); - image$intercept_packets$actionbar = config.getBoolean("image.intercept-packets.actionbar", true); - image$intercept_packets$title = config.getBoolean("image.intercept-packets.title", true); - image$intercept_packets$bossbar = config.getBoolean("image.intercept-packets.bossbar", true); - image$intercept_packets$container = config.getBoolean("image.intercept-packets.container", true); - image$intercept_packets$team = config.getBoolean("image.intercept-packets.team", true); - image$intercept_packets$scoreboard = config.getBoolean("image.intercept-packets.scoreboard", true); - image$intercept_packets$entity_name = config.getBoolean("image.intercept-packets.entity-name", false); - image$intercept_packets$text_display = config.getBoolean("image.intercept-packets.text-display", true); - image$intercept_packets$armor_stand = config.getBoolean("image.intercept-packets.armor-stand", true); - 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); + + network$intercept_packets$system_chat = config.getBoolean("network.intercept-packets.system-chat", true); + network$intercept_packets$tab_list = config.getBoolean("network.intercept-packets.tab-list", true); + network$intercept_packets$actionbar = config.getBoolean("network.intercept-packets.actionbar", true); + network$intercept_packets$title = config.getBoolean("network.intercept-packets.title", true); + network$intercept_packets$bossbar = config.getBoolean("network.intercept-packets.bossbar", true); + network$intercept_packets$container = config.getBoolean("network.intercept-packets.container", true); + network$intercept_packets$team = config.getBoolean("network.intercept-packets.team", true); + network$intercept_packets$scoreboard = config.getBoolean("network.intercept-packets.scoreboard", true); + network$intercept_packets$entity_name = config.getBoolean("network.intercept-packets.entity-name", false); + network$intercept_packets$text_display = config.getBoolean("network.intercept-packets.text-display", true); + network$intercept_packets$armor_stand = config.getBoolean("network.intercept-packets.armor-stand", true); + network$intercept_packets$player_info = config.getBoolean("network.intercept-packets.player-info", true); + network$intercept_packets$set_score = config.getBoolean("network.intercept-packets.set-score", true); + network$intercept_packets$item = config.getBoolean("network.intercept-packets.item", true); + network$intercept_packets$advancement = config.getBoolean("network.intercept-packets.advancement", true); // emoji emoji$contexts$chat = config.getBoolean("emoji.contexts.chat", true); @@ -729,63 +730,63 @@ public class Config { } public static boolean interceptSystemChat() { - return instance.image$intercept_packets$system_chat; + return instance.network$intercept_packets$system_chat; } public static boolean interceptTabList() { - return instance.image$intercept_packets$tab_list; + return instance.network$intercept_packets$tab_list; } public static boolean interceptActionBar() { - return instance.image$intercept_packets$actionbar; + return instance.network$intercept_packets$actionbar; } public static boolean interceptTitle() { - return instance.image$intercept_packets$title; + return instance.network$intercept_packets$title; } public static boolean interceptBossBar() { - return instance.image$intercept_packets$bossbar; + return instance.network$intercept_packets$bossbar; } public static boolean interceptContainer() { - return instance.image$intercept_packets$container; + return instance.network$intercept_packets$container; } public static boolean interceptTeam() { - return instance.image$intercept_packets$team; + return instance.network$intercept_packets$team; } public static boolean interceptEntityName() { - return instance.image$intercept_packets$entity_name; + return instance.network$intercept_packets$entity_name; } public static boolean interceptScoreboard() { - return instance.image$intercept_packets$scoreboard; + return instance.network$intercept_packets$scoreboard; } public static boolean interceptTextDisplay() { - return instance.image$intercept_packets$text_display; + return instance.network$intercept_packets$text_display; } public static boolean interceptArmorStand() { - return instance.image$intercept_packets$armor_stand; + return instance.network$intercept_packets$armor_stand; } public static boolean interceptPlayerInfo() { - return instance.image$intercept_packets$player_info; + return instance.network$intercept_packets$player_info; } public static boolean interceptSetScore() { - return instance.image$intercept_packets$set_score; + return instance.network$intercept_packets$set_score; } public static boolean interceptItem() { - return instance.image$intercept_packets$item; + return instance.network$intercept_packets$item; } public static boolean interceptAdvancement() { - return instance.image$intercept_packets$advancement; + return instance.network$intercept_packets$advancement; } public static boolean predictBreaking() { From 6ed54af7ab634675ef451bfee01a86e18fc6bcfe Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 19 Sep 2025 09:16:26 +0800 Subject: [PATCH 025/125] =?UTF-8?q?feat(block):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E6=96=B9=E5=9D=97=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/BukkitBlockBehaviors.java | 4 + .../block/behavior/ButtonBlockBehavior.java | 217 ++++++++++++++++++ .../DirectionalAttachedBlockBehavior.java | 20 +- ...hedHorizontalDirectionalBlockBehavior.java | 150 ++++++++++++ .../behavior/PressurePlateBlockBehavior.java | 7 +- .../item/recipe/BukkitRecipeManager.java | 2 +- .../plugin/network/BukkitNetworkManager.java | 9 +- .../reflection/minecraft/CoreReflections.java | 6 + .../minecraft/MBuiltInRegistries.java | 5 + .../reflection/minecraft/MEntitySelector.java | 12 + .../reflection/minecraft/MGameEvent.java | 15 ++ .../craftengine/core/block/BlockBehavior.java | 10 +- .../core/block/properties/Properties.java | 2 + .../block/state/properties/AttachFace.java | 7 + gradle.properties | 2 +- 15 files changed, 444 insertions(+), 24 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelector.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvent.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AttachFace.java 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 4070b0f48..fc8ba1cc6 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 @@ -37,6 +37,8 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key SIMPLE_PARTICLE_BLOCK = Key.from("craftengine:simple_particle_block"); public static final Key WALL_TORCH_PARTICLE_BLOCK = Key.from("craftengine:wall_torch_particle_block"); public static final Key FENCE_BLOCK = Key.from("craftengine:fence_block"); + public static final Key BUTTON_BLOCK = Key.from("craftengine:button_block"); + public static final Key FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK = Key.from("craftengine:face_attached_horizontal_directional_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -72,5 +74,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(SIMPLE_PARTICLE_BLOCK, SimpleParticleBlockBehavior.FACTORY); register(WALL_TORCH_PARTICLE_BLOCK, WallTorchParticleBlockBehavior.FACTORY); register(FENCE_BLOCK, FenceBlockBehavior.FACTORY); + register(BUTTON_BLOCK, ButtonBlockBehavior.FACTORY); + register(FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK, FaceAttachedHorizontalDirectionalBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java new file mode 100644 index 000000000..3be8fa890 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java @@ -0,0 +1,217 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntitySelector; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MGameEvent; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.BooleanProperty; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.entity.player.InteractionResult; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.sound.SoundData; +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.HorizontalDirection; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; + +import javax.annotation.Nullable; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Callable; + +public class ButtonBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final BooleanProperty poweredProperty; + private final int ticksToStayPressed; + private final boolean canButtonBeActivatedByArrows; + private final SoundData buttonClickOnSound; + private final SoundData buttonClickOffSound; + + public ButtonBlockBehavior(CustomBlock customBlock, + BooleanProperty powered, + int ticksToStayPressed, + boolean canButtonBeActivatedByArrows, + SoundData buttonClickOnSound, + SoundData buttonClickOffSound) { + super(customBlock); + this.poweredProperty = powered; + this.ticksToStayPressed = ticksToStayPressed; + this.canButtonBeActivatedByArrows = canButtonBeActivatedByArrows; + this.buttonClickOnSound = buttonClickOnSound; + this.buttonClickOffSound = buttonClickOffSound; + } + + @Override + public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) { + if (!state.get(this.poweredProperty)) { + press(BlockStateUtils.getBlockOwner(state.customBlockState().literalObject()), + state, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), + context.getPlayer() != null ? context.getPlayer().serverPlayer() : null); + return InteractionResult.SUCCESS_AND_CANCEL; + } + return InteractionResult.PASS; + } + + @Override + public void onExplosionHit(Object thisBlock, Object[] args, Callable superMethod) { + ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + if (blockState == null) return; + if (FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3]) && !blockState.get(this.poweredProperty)) { + press(thisBlock, blockState, args[1], args[2], null); + } + } + + @Override + public void affectNeighborsAfterRemoval(Object thisBlock, Object[] args, Callable superMethod) { + ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + if (blockState == null) return; + if (!(boolean) args[3] && blockState.get(this.poweredProperty)) { + updateNeighbours(thisBlock, blockState, args[1], args[2]); + } + } + + @Override + public void onRemove(Object thisBlock, Object[] args, Callable superMethod) { + ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + if (blockState == null) return; + if (!(boolean) args[4] && blockState.get(this.poweredProperty)) { + updateNeighbours(thisBlock, blockState, args[1], args[2]); + } + } + + @Override + public int getSignal(Object thisBlock, Object[] args, Callable superMethod) { + ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + if (blockState == null) return 0; + return blockState.get(this.poweredProperty) ? 15 : 0; + } + + @Override + public int getDirectSignal(Object thisBlock, Object[] args, Callable superMethod) { + ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); + if (blockState == null) return 0; + return blockState.get(this.poweredProperty) + && FaceAttachedHorizontalDirectionalBlockBehavior.getConnectedDirection(blockState) + == DirectionUtils.fromNMSDirection(args[3]) ? 15 : 0; + } + + @Override + public boolean isSignalSource(Object thisBlock, Object[] args, Callable superMethod) { + return true; + } + + @Override + public void tick(Object thisBlock, Object[] args, Callable superMethod) { + Object state = args[0]; + Object level = args[1]; + Object pos = args[2]; + ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); + if (blockState == null) return; + if (blockState.get(this.poweredProperty)) { + checkPressed(thisBlock, state, level, pos); + } + } + + @Override + public void entityInside(Object thisBlock, Object[] args, Callable superMethod) { + Object state = args[0]; + Object level = args[1]; + Object pos = args[2]; + ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); + if (blockState == null) return; + if (this.canButtonBeActivatedByArrows && !blockState.get(this.poweredProperty)) { + checkPressed(thisBlock, state, level, pos); + } + } + + private void checkPressed(Object thisBlock, Object state, Object level, Object pos) { + Object abstractArrow = this.canButtonBeActivatedByArrows ? FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass( + level, CoreReflections.clazz$AbstractArrow, FastNMS.INSTANCE.method$AABB$move( + FastNMS.INSTANCE.method$VoxelShape$bounds(FastNMS.INSTANCE.method$BlockState$getShape( + state, level, pos, CoreReflections.instance$CollisionContext$empty + )), pos), MEntitySelector.NO_SPECTATORS).stream().findFirst().orElse(null) : null; + boolean flag = abstractArrow != null; + ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); + if (blockState == null) return; + boolean poweredValue = blockState.get(this.poweredProperty); + if (flag != poweredValue) { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, blockState.with(this.poweredProperty, flag).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); + updateNeighbours(thisBlock, blockState, level, pos); + playSound(null, level, pos, flag); + Object gameEvent = VersionHelper.isOrAbove1_20_5() + ? FastNMS.INSTANCE.method$Holder$direct(flag ? MGameEvent.BLOCK_ACTIVATE : MGameEvent.BLOCK_DEACTIVATE) + : flag ? MGameEvent.BLOCK_ACTIVATE : MGameEvent.BLOCK_DEACTIVATE; + FastNMS.INSTANCE.method$LevelAccessor$gameEvent(level, abstractArrow, gameEvent, pos); + } + + if (flag) { + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.ticksToStayPressed); + } + } + + private void updateNeighbours(Object thisBlock, ImmutableBlockState state, Object level, Object pos) { + Direction direction = FaceAttachedHorizontalDirectionalBlockBehavior.getConnectedDirection(state); + if (direction == null) return; + Direction opposite = direction.opposite(); + Object nmsDirection = DirectionUtils.toNMSDirection(opposite); + Object orientation = null; + if (VersionHelper.isOrAbove1_21_2()) { + @SuppressWarnings("unchecked") + Property facing = (Property) state.owner().value().getProperty("facing"); + if (facing != null) { + orientation = FastNMS.INSTANCE.method$ExperimentalRedstoneUtils$initialOrientation( + level, nmsDirection, opposite.axis().isHorizontal() ? CoreReflections.instance$Direction$UP : DirectionUtils.toNMSDirection(state.get(facing).toDirection()) + ); + } + } + FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, pos, thisBlock, orientation); + FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, FastNMS.INSTANCE.method$BlockPos$relative(pos, nmsDirection), thisBlock, orientation); + } + + private void playSound(@Nullable Object player, Object level, Object pos, boolean hitByArrow) { + SoundData soundData = getSound(hitByArrow); + if (soundData == null) return; + Object sound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(soundData.id()), Optional.empty()); + FastNMS.INSTANCE.method$LevelAccessor$playSound(level, player, pos, sound, CoreReflections.instance$SoundSource$BLOCKS, soundData.volume().get(), soundData.pitch().get()); + } + + private SoundData getSound(boolean isOn) { + return isOn ? this.buttonClickOnSound : this.buttonClickOffSound; + } + + private void press(Object thisBlock, ImmutableBlockState state, Object level, Object pos, @Nullable Object player) { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, state.with(this.poweredProperty, true).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.ticksToStayPressed); + playSound(player, level, pos, true); + Object gameEvent = VersionHelper.isOrAbove1_20_5() ? FastNMS.INSTANCE.method$Holder$direct(MGameEvent.BLOCK_ACTIVATE) : MGameEvent.BLOCK_ACTIVATE; + FastNMS.INSTANCE.method$LevelAccessor$gameEvent(level, player, gameEvent, pos); + } + + public static class Factory implements BlockBehaviorFactory { + + @SuppressWarnings({"unchecked", "DuplicatedCode"}) + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + BooleanProperty powered = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.button.missing_powered"); + int ticksToStayPressed = ResourceConfigUtils.getAsInt(arguments.getOrDefault("ticks-to-stay-pressed", 30), "ticks-to-stay-pressed"); + boolean canButtonBeActivatedByArrows = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-button-be-activated-by-arrows", true), "can-button-be-activated-by-arrows"); + Map sounds = (Map) arguments.get("sounds"); + SoundData buttonClickOnSound = null; + SoundData buttonClickOffSound = null; + if (sounds != null) { + buttonClickOnSound = Optional.ofNullable(sounds.get("on")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null); + buttonClickOffSound = Optional.ofNullable(sounds.get("off")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null); + } + return new ButtonBlockBehavior(block, powered, ticksToStayPressed, canButtonBeActivatedByArrows, buttonClickOnSound, buttonClickOffSound); + } + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java index a155235db..f2e4d9987 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java @@ -25,7 +25,7 @@ import org.bukkit.Registry; import java.util.*; import java.util.concurrent.Callable; -public class DirectionalAttachedBlockBehavior extends AbstractCanSurviveBlockBehavior { +public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property facingProperty; private final boolean isSixDirection; @@ -37,12 +37,11 @@ public class DirectionalAttachedBlockBehavior extends AbstractCanSurviveBlockBeh public DirectionalAttachedBlockBehavior(CustomBlock customBlock, Property facingProperty, boolean isSixDirection, - int delay, boolean blacklist, List tagsCanSurviveOn, Set blockStatesCanSurviveOn, Set customBlocksCansSurviveOn) { - super(customBlock, delay); + super(customBlock); this.facingProperty = facingProperty; this.isSixDirection = isSixDirection; this.tagsCanSurviveOn = tagsCanSurviveOn; @@ -69,8 +68,8 @@ public class DirectionalAttachedBlockBehavior extends AbstractCanSurviveBlockBeh } @Override - protected boolean canSurvive(Object thisBlock, Object blockState, Object world, Object pos) throws Exception { - ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(blockState).orElse(null); + public boolean canSurvive(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); if (state == null) return false; DirectionalAttachedBlockBehavior behavior = state.behavior().getAs(DirectionalAttachedBlockBehavior.class).orElse(null); if (behavior == null) return false; @@ -80,10 +79,10 @@ public class DirectionalAttachedBlockBehavior extends AbstractCanSurviveBlockBeh } else { direction = ((HorizontalDirection) state.get(behavior.facingProperty)).opposite().toDirection(); } - BlockPos blockPos = LocationUtils.fromBlockPos(pos).relative(direction); + BlockPos blockPos = LocationUtils.fromBlockPos(args[2]).relative(direction); Object nmsPos = LocationUtils.toBlockPos(blockPos); - Object nmsState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, nmsPos); - return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(nmsState, world, nmsPos, DirectionUtils.toNMSDirection(direction), CoreReflections.instance$SupportType$FULL) + Object nmsState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(args[1], nmsPos); + return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy(nmsState, args[1], nmsPos, DirectionUtils.toNMSDirection(direction), CoreReflections.instance$SupportType$FULL) && mayPlaceOn(nmsState); } @@ -144,14 +143,13 @@ public class DirectionalAttachedBlockBehavior extends AbstractCanSurviveBlockBeh throw new LocalizedResourceConfigException("warning.config.block.behavior.directional_attached.missing_facing"); } Tuple, Set, Set> tuple = readTagsAndState(arguments); - int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", true), "blacklist"); - return new DirectionalAttachedBlockBehavior(block, facing, isDirection, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right()); + return new DirectionalAttachedBlockBehavior(block, facing, isDirection, blacklistMode, tuple.left(), tuple.mid(), tuple.right()); } } @SuppressWarnings("DuplicatedCode") - private static Tuple, Set, Set> readTagsAndState(Map arguments) { + public static Tuple, Set, Set> readTagsAndState(Map arguments) { List mcTags = new ArrayList<>(); for (String tag : MiscUtils.getAsStringList(arguments.getOrDefault("attached-block-tags", List.of()))) { mcTags.add(BlockTags.getOrCreate(Key.of(tag))); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java new file mode 100644 index 000000000..cc877ef06 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java @@ -0,0 +1,150 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +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.DirectionUtils; +import net.momirealms.craftengine.bukkit.util.LocationUtils; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.block.state.properties.AttachFace; +import net.momirealms.craftengine.core.item.context.BlockPlaceContext; +import net.momirealms.craftengine.core.util.Direction; +import net.momirealms.craftengine.core.util.HorizontalDirection; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.Tuple; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Callable; + +public class FaceAttachedHorizontalDirectionalBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final Property attachFaceProperty; + private final Property facingProperty; + private final List tagsCanSurviveOn; + private final Set blockStatesCanSurviveOn; + private final Set customBlocksCansSurviveOn; + private final boolean blacklistMode; + + public FaceAttachedHorizontalDirectionalBlockBehavior(CustomBlock customBlock, + boolean blacklist, + List tagsCanSurviveOn, + Set blockStatesCanSurviveOn, + Set customBlocksCansSurviveOn, + Property attachFace, + Property facing) { + super(customBlock); + this.tagsCanSurviveOn = tagsCanSurviveOn; + this.blockStatesCanSurviveOn = blockStatesCanSurviveOn; + this.customBlocksCansSurviveOn = customBlocksCansSurviveOn; + this.blacklistMode = blacklist; + this.attachFaceProperty = attachFace; + this.facingProperty = facing; + } + + @Override + public boolean canSurvive(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Direction direction = getConnectedDirection(BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null)); + if (direction == null) return false; + direction = direction.opposite(); + Object nmsDirection = DirectionUtils.toNMSDirection(direction); + Object targetPos = FastNMS.INSTANCE.method$BlockPos$relative(args[2], nmsDirection); + Object targetState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(args[1], targetPos); + return canAttach(args[1], targetPos, nmsDirection, targetState) && mayPlaceOn(targetState); + } + + @SuppressWarnings("unchecked") + @Override + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { + Property face = (Property) state.owner().value().getProperty("face"); + Property facing = (Property) state.owner().value().getProperty("facing"); + if (face == null || facing == null) return null; + for (Direction direction : context.getNearestLookingDirections()) { + if (direction.axis() == Direction.Axis.Y) { + state = state + .with(face, direction == Direction.UP ? AttachFace.CEILING : AttachFace.FLOOR) + .with(facing, context.getHorizontalDirection().toHorizontalDirection()); + } else { + state = state.with(face, AttachFace.WALL).with(facing, direction.opposite().toHorizontalDirection()); + } + if (FastNMS.INSTANCE.method$BlockStateBase$canSurvive(state.customBlockState().literalObject(), context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()))) { + return state; + } + } + return null; + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Direction direction = getConnectedDirection(BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null)); + if (direction == null) return MBlocks.AIR$defaultState; + if (DirectionUtils.toNMSDirection(direction.opposite()) == args[updateShape$direction] && !FastNMS.INSTANCE.method$BlockStateBase$canSurvive(args[0], args[updateShape$level], args[updateShape$blockPos])) { + return MBlocks.AIR$defaultState; + } + return superMethod.call(); + } + + private boolean mayPlaceOn(Object state) { + for (Object tag : this.tagsCanSurviveOn) { + if (FastNMS.INSTANCE.method$BlockStateBase$is(state, tag)) { + return !this.blacklistMode; + } + } + Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state); + if (optionalCustomState.isEmpty()) { + if (!this.blockStatesCanSurviveOn.isEmpty() && this.blockStatesCanSurviveOn.contains(state)) { + return !this.blacklistMode; + } + } else { + ImmutableBlockState belowCustomState = optionalCustomState.get(); + if (this.customBlocksCansSurviveOn.contains(belowCustomState.owner().value().id().toString())) { + return !this.blacklistMode; + } + if (this.customBlocksCansSurviveOn.contains(belowCustomState.toString())) { + return !this.blacklistMode; + } + } + return this.blacklistMode; + } + + public static boolean canAttach(Object level, Object targetPos, Object direction, Object targetState) { + return FastNMS.INSTANCE.method$BlockStateBase$isFaceSturdy( + targetState, level, targetPos, + FastNMS.INSTANCE.method$Direction$getOpposite(direction), + CoreReflections.instance$SupportType$FULL + ); + } + + @Nullable + public static Direction getConnectedDirection(ImmutableBlockState state) { + if (state == null) return null; + FaceAttachedHorizontalDirectionalBlockBehavior behavior = state.behavior().getAs(FaceAttachedHorizontalDirectionalBlockBehavior.class).orElse(null); + if (behavior == null) return null; + return switch (state.get(behavior.attachFaceProperty)) { + case CEILING -> Direction.DOWN; + case FLOOR -> Direction.UP; + default -> state.get(behavior.facingProperty).toDirection(); + }; + } + + public static class Factory implements BlockBehaviorFactory { + + @SuppressWarnings("unchecked") + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Property attachFace = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("face"), "warning.config.block.behavior.face_attached_horizontal_directional.missing_face"); + Property facing = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.face_attached_horizontal_directional.missing_facing"); + Tuple, Set, Set> tuple = DirectionalAttachedBlockBehavior.readTagsAndState(arguments); + boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", true), "blacklist"); + return new FaceAttachedHorizontalDirectionalBlockBehavior(block, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), attachFace, facing); + } + } +} 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 09c8c920d..5ec5cc268 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 @@ -4,6 +4,7 @@ import io.papermc.paper.event.entity.EntityInsideBlockEvent; 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.plugin.reflection.minecraft.MEntitySelector; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.EventUtils; @@ -28,6 +29,7 @@ import javax.annotation.Nullable; import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; +import java.util.function.Predicate; public class PressurePlateBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); @@ -111,7 +113,10 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { case MOBS -> CoreReflections.clazz$LivingEntity; }; Object box = FastNMS.INSTANCE.method$AABB$move(CoreReflections.instance$BasePressurePlateBlock$TOUCH_AABB, pos); - return FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass(level, box, clazz) > 0 ? 15 : 0; + return !FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass( + level, clazz, box, + MEntitySelector.NO_SPECTATORS.and(entity -> !FastNMS.INSTANCE.method$Entity$isIgnoringBlockTriggers(entity)) + ).isEmpty() ? 15 : 0; } private Object setSignalForState(Object state, int strength) { 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 06d11bf38..e385ffca4 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 @@ -395,7 +395,7 @@ public class BukkitRecipeManager extends AbstractRecipeManager { JsonObject jsonObject = entry.getValue(); Key serializerType = Key.of(jsonObject.get("type").getAsString()); - // noinspection unchecked + @SuppressWarnings("unchecked") RecipeSerializer> serializer = (RecipeSerializer>) BuiltInRegistries.RECIPE_SERIALIZER.getValue(serializerType); if (serializer == null) { continue; 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 2952fe1bc..4671b7ed5 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 @@ -961,6 +961,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes */ public static class HelloListener implements NMSPacketListener { + @SuppressWarnings("unchecked") @Override public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { BukkitServerPlayer player = (BukkitServerPlayer) user; @@ -984,7 +985,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } else { Optional uuid; try { - // noinspection unchecked uuid = (Optional) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); } catch (Throwable t) { CraftEngine.instance().logger().severe("Failed to get uuid from ServerboundHelloPacket", t); @@ -1478,6 +1478,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public static class EditBookListener implements NMSPacketListener { + @SuppressWarnings("unchecked") @Override public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { if (!Config.filterBook()) return; @@ -1492,7 +1493,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes List pages; try { - // noinspection unchecked pages = (List) NetworkReflections.methodHandle$ServerboundEditBookPacket$pagesGetter.invokeExact(packet); } catch (Throwable t) { CraftEngine.instance().logger().warn("Failed to get pages from ServerboundEditBookPacket", t); @@ -1501,7 +1501,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes List newPages = new ArrayList<>(pages.size()); Optional title; try { - // noinspection unchecked title = (Optional) NetworkReflections.methodHandle$ServerboundEditBookPacket$titleGetter.invokeExact(packet); } catch (Throwable t) { CraftEngine.instance().logger().warn("Failed to get title from ServerboundEditBookPacket", t); @@ -1733,6 +1732,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes public static class FinishConfigurationListener implements NMSPacketListener { + @SuppressWarnings("unchecked") @Override public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { if (!VersionHelper.isOrAbove1_20_2() || !Config.sendPackOnJoin()) { @@ -1793,7 +1793,6 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } Queue configurationTasks; try { - // noinspection unchecked 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); @@ -3665,7 +3664,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); if (entityDataId != BaseEntityData.CustomName.id()) continue; - // noinspection unchecked + @SuppressWarnings("unchecked") Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (optionalTextComponent.isEmpty()) continue; Object textComponent = optionalTextComponent.get(); 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 859f826ed..4fb178606 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 @@ -4400,4 +4400,10 @@ public final class CoreReflections { "world.level.block.FenceGateBlock" ) ); + + public static final Class clazz$GameEvent = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("world.level.gameevent.GameEvent") + ) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java index ef6d7a8b1..565ae69c3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBuiltInRegistries.java @@ -22,6 +22,7 @@ public final class MBuiltInRegistries { public static final Object PARTICLE_TYPE; public static final Object DATA_COMPONENT_TYPE; public static final Object LOOT_POOL_ENTRY_TYPE; + public static final Object GAME_EVENT; static { Field[] fields = CoreReflections.clazz$BuiltInRegistries.getDeclaredFields(); @@ -37,6 +38,7 @@ public final class MBuiltInRegistries { Object registries$RecipeType = null; Object registries$DataComponentType = null; Object registries$LootPoolEntryType = null; + Object registries$GameEvent = null; for (Field field : fields) { Type fieldType = field.getGenericType(); if (fieldType instanceof ParameterizedType paramType) { @@ -67,6 +69,8 @@ public final class MBuiltInRegistries { registries$Fluid = field.get(null); } else if (type == CoreReflections.clazz$LootPoolEntryType) { registries$LootPoolEntryType = field.get(null); + } else if (type == CoreReflections.clazz$GameEvent) { + registries$GameEvent = field.get(null); } } } @@ -82,6 +86,7 @@ public final class MBuiltInRegistries { RECIPE_TYPE = requireNonNull(registries$RecipeType); LOOT_POOL_ENTRY_TYPE = requireNonNull(registries$LootPoolEntryType); DATA_COMPONENT_TYPE = registries$DataComponentType; + GAME_EVENT = requireNonNull(registries$GameEvent); } catch (ReflectiveOperationException e) { throw new ReflectionInitException("Failed to init BuiltInRegistries", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelector.java new file mode 100644 index 000000000..7a2b43ab7 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelector.java @@ -0,0 +1,12 @@ +package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; + +import java.util.function.Predicate; + +public final class MEntitySelector { + private MEntitySelector() {} + + public static final Predicate NO_SPECTATORS = entity -> !FastNMS.INSTANCE.method$Entity$isSpectator(entity); + +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvent.java new file mode 100644 index 000000000..500f39d8c --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvent.java @@ -0,0 +1,15 @@ +package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; + +public final class MGameEvent { + private MGameEvent() {} + + public static final Object BLOCK_ACTIVATE = getById("block_activate"); + public static final Object BLOCK_DEACTIVATE = getById("block_deactivate"); + + private static Object getById(String id) { + Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); + return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.GAME_EVENT, rl); + } +} 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 f1aba39ce..e969cab8c 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 @@ -55,18 +55,18 @@ public abstract class BlockBehavior { superMethod.call(); } - // ServerLevel level, BlockPos pos, RandomSource random + // BlockState state, ServerLevel level, BlockPos pos, RandomSource random public void tick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { superMethod.call(); } - // ServerLevel level, BlockPos pos, RandomSource random + // BlockState state, ServerLevel level, BlockPos pos, RandomSource random public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { superMethod.call(); } // 1.20-1.20.4 BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify, UseOnContext context - // 1.20.5+ Level level, BlockPos pos, BlockState oldState, boolean movedByPiston + // 1.20.5+ BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston public void onPlace(Object thisBlock, Object[] args, Callable superMethod) throws Exception { superMethod.call(); } @@ -95,12 +95,12 @@ public abstract class BlockBehavior { return false; } - //BlockState state + // BlockState state public boolean hasAnalogOutputSignal(Object thisBlock, Object[] args) throws Exception { return false; } - //BlockState state, Level level, BlockPos pos + // BlockState state, Level level, BlockPos pos public int getAnalogOutputSignal(Object thisBlock, Object[] args) throws Exception { return 0; } 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 e5a143264..e559a080a 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 @@ -22,6 +22,7 @@ public final class Properties { public static final Key STAIRS_SHAPE = Key.of("craftengine:stairs_shape"); public static final Key SLAB_TYPE = Key.of("craftengine:slab_type"); public static final Key SOFA_SHAPE = Key.of("craftengine:sofa_shape"); + public static final Key ATTACH_FACE = Key.of("craftengine:attach_face"); static { register(BOOLEAN, BooleanProperty.FACTORY); @@ -38,6 +39,7 @@ public final class Properties { register(STAIRS_SHAPE, new EnumProperty.Factory<>(StairsShape.class)); register(SLAB_TYPE, new EnumProperty.Factory<>(SlabType.class)); register(SOFA_SHAPE, new EnumProperty.Factory<>(SofaShape.class)); + register(ATTACH_FACE, new EnumProperty.Factory<>(AttachFace.class)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AttachFace.java b/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AttachFace.java new file mode 100644 index 000000000..de9d6267b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AttachFace.java @@ -0,0 +1,7 @@ +package net.momirealms.craftengine.core.block.state.properties; + +public enum AttachFace { + FLOOR, + WALL, + CEILING +} diff --git a/gradle.properties b/gradle.properties index e6e8440a9..e0c51c8a7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.91 +nms_helper_version=1.0.92 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1 From 1d500a580de7b39a5bbcf2945d813379e0b1aa88 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 19 Sep 2025 09:59:40 +0800 Subject: [PATCH 026/125] =?UTF-8?q?fix(block):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E7=9A=84tick=E6=96=B9=E5=9D=97=E6=96=B9?= =?UTF-8?q?=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 这个逆天问题,终于被我解决了真的是折磨死我了 - 解释下是如何解决的,因为ce是一个方块一个状态,所以说直接拿获取到的thisblock去tick方块会导致前面如果你做了一个setblock来更新ce内部的方块状态就会导致thisblock和实际tick的这个方块对不上然后导致tick失效,需要在setblock拿一下设置的方块状态然后重新获取正确的block才能被之前tick,这次更新顺手把压力板修了,之前用的是不正确的解决方案,然后修复下保险箱的切换 - 啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊漏电了(不是 --- .../block/behavior/ButtonBlockBehavior.java | 26 +++++++++------- .../behavior/PressurePlateBlockBehavior.java | 20 ++++++------ .../entity/SimpleStorageBlockEntity.java | 31 +++++++++++-------- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java index 3be8fa890..7bca026c1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java @@ -53,8 +53,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { @Override public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) { if (!state.get(this.poweredProperty)) { - press(BlockStateUtils.getBlockOwner(state.customBlockState().literalObject()), - state, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), + press(state, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), context.getPlayer() != null ? context.getPlayer().serverPlayer() : null); return InteractionResult.SUCCESS_AND_CANCEL; } @@ -66,7 +65,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); if (blockState == null) return; if (FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3]) && !blockState.get(this.poweredProperty)) { - press(thisBlock, blockState, args[1], args[2], null); + press(blockState, args[1], args[2], null); } } @@ -117,7 +116,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); if (blockState == null) return; if (blockState.get(this.poweredProperty)) { - checkPressed(thisBlock, state, level, pos); + checkPressed(state, level, pos); } } @@ -129,11 +128,12 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); if (blockState == null) return; if (this.canButtonBeActivatedByArrows && !blockState.get(this.poweredProperty)) { - checkPressed(thisBlock, state, level, pos); + checkPressed(state, level, pos); } } - private void checkPressed(Object thisBlock, Object state, Object level, Object pos) { + private void checkPressed(Object state, Object level, Object pos) { + Object tickState = state; Object abstractArrow = this.canButtonBeActivatedByArrows ? FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass( level, CoreReflections.clazz$AbstractArrow, FastNMS.INSTANCE.method$AABB$move( FastNMS.INSTANCE.method$VoxelShape$bounds(FastNMS.INSTANCE.method$BlockState$getShape( @@ -144,8 +144,9 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { if (blockState == null) return; boolean poweredValue = blockState.get(this.poweredProperty); if (flag != poweredValue) { - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, blockState.with(this.poweredProperty, flag).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); - updateNeighbours(thisBlock, blockState, level, pos); + tickState = blockState.with(this.poweredProperty, flag).customBlockState().literalObject(); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, tickState, UpdateOption.UPDATE_ALL.flags()); + updateNeighbours(BlockStateUtils.getBlockOwner(tickState), blockState, level, pos); playSound(null, level, pos, flag); Object gameEvent = VersionHelper.isOrAbove1_20_5() ? FastNMS.INSTANCE.method$Holder$direct(flag ? MGameEvent.BLOCK_ACTIVATE : MGameEvent.BLOCK_DEACTIVATE) @@ -154,7 +155,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { } if (flag) { - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.ticksToStayPressed); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(tickState), this.ticksToStayPressed); } } @@ -188,9 +189,10 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { return isOn ? this.buttonClickOnSound : this.buttonClickOffSound; } - private void press(Object thisBlock, ImmutableBlockState state, Object level, Object pos, @Nullable Object player) { - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, state.with(this.poweredProperty, true).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.ticksToStayPressed); + private void press(ImmutableBlockState state, Object level, Object pos, @Nullable Object player) { + Object tickState = state.with(this.poweredProperty, true).customBlockState().literalObject(); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, tickState, UpdateOption.UPDATE_ALL.flags()); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(tickState), this.ticksToStayPressed); playSound(player, level, pos, true); Object gameEvent = VersionHelper.isOrAbove1_20_5() ? FastNMS.INSTANCE.method$Holder$direct(MGameEvent.BLOCK_ACTIVATE) : MGameEvent.BLOCK_ACTIVATE; FastNMS.INSTANCE.method$LevelAccessor$gameEvent(level, player, gameEvent, pos); 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 5ec5cc268..a3e85d6ae 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 @@ -29,7 +29,6 @@ import javax.annotation.Nullable; import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; -import java.util.function.Predicate; public class PressurePlateBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); @@ -87,7 +86,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { Object state = args[0]; int signalForState = this.getSignalForState(state); if (signalForState > 0) { - this.checkPressed(null, args[1], args[2], state, signalForState, thisBlock); + this.checkPressed(null, args[1], args[2], state, signalForState); } } @@ -101,9 +100,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { Object state = args[0]; int signalForState = this.getSignalForState(state); if (signalForState == 0) { - this.checkPressed(args[3], args[1], args[2], state, signalForState, thisBlock); - } else { - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime); + this.checkPressed(args[3], args[1], args[2], state, signalForState); } } @@ -125,16 +122,17 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { return optionalCustomState.get().with(this.poweredProperty, strength > 0).customBlockState().literalObject(); } - private void checkPressed(@Nullable Object entity, Object level, Object pos, Object state, int currentSignal, Object thisBlock) { + private void checkPressed(@Nullable Object entity, Object level, Object pos, Object state, int currentSignal) { + Object tickState = state; int signalStrength = this.getSignalStrength(level, pos); boolean wasActive = currentSignal > 0; boolean isActive = signalStrength > 0; if (currentSignal != signalStrength) { - Object blockState = this.setSignalForState(state, signalStrength); - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, blockState, 2); - this.updateNeighbours(level, pos, thisBlock); - FastNMS.INSTANCE.method$Level$setBlocksDirty(level, pos, state, blockState); + tickState = this.setSignalForState(state, signalStrength); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, tickState, 2); + this.updateNeighbours(level, pos, BlockStateUtils.getBlockOwner(tickState)); + FastNMS.INSTANCE.method$Level$setBlocksDirty(level, pos, state, tickState); } org.bukkit.World craftWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(level); @@ -150,7 +148,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { } if (isActive) { - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.pressedTime); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(tickState), this.pressedTime); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java index fcb654c71..f889df503 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java @@ -107,8 +107,8 @@ public class SimpleStorageBlockEntity extends BlockEntity { // 有非观察者的人,那么就不触发开启音效和事件 if (!hasNoViewer(this.inventory.getViewers())) return; this.maxInteractionDistance = Math.max(player.getCachedInteractionRange(), this.maxInteractionDistance); - this.setOpen(player); - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(super.world.world().serverWorld(), LocationUtils.toBlockPos(this.pos), BlockStateUtils.getBlockOwner(this.blockState.customBlockState().literalObject()), 5); + ImmutableBlockState state = this.setOpen(player); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(super.world.world().serverWorld(), LocationUtils.toBlockPos(this.pos), BlockStateUtils.getBlockOwner(state.customBlockState().literalObject()), 5); } } @@ -127,8 +127,8 @@ public class SimpleStorageBlockEntity extends BlockEntity { } } - private void setOpen(@Nullable Player player) { - this.updateOpenBlockState(true); + private ImmutableBlockState setOpen(@Nullable Player player) { + ImmutableBlockState state = this.updateOpenBlockState(true); org.bukkit.World bukkitWorld = (org.bukkit.World) super.world.world().platformWorld(); if (player != null) { bukkitWorld.sendGameEvent((org.bukkit.entity.Player) player.platformPlayer(), GameEvent.CONTAINER_OPEN, new Vector(this.pos.x(), this.pos.y(), this.pos.z())); @@ -140,10 +140,11 @@ public class SimpleStorageBlockEntity extends BlockEntity { if (soundData != null) { super.world.world().playBlockSound(Vec3d.atCenterOf(this.pos), soundData); } + return state; } - private void setClose(@Nullable Player player) { - this.updateOpenBlockState(false); + private ImmutableBlockState setClose(@Nullable Player player) { + ImmutableBlockState state = this.updateOpenBlockState(false); org.bukkit.World bukkitWorld = (org.bukkit.World) super.world.world().platformWorld(); if (player != null) { bukkitWorld.sendGameEvent((org.bukkit.entity.Player) player.platformPlayer(), GameEvent.CONTAINER_CLOSE, new Vector(this.pos.x(), this.pos.y(), this.pos.z())); @@ -155,6 +156,7 @@ public class SimpleStorageBlockEntity extends BlockEntity { if (soundData != null) { super.world.world().playBlockSound(Vec3d.atCenterOf(this.pos), soundData); } + return state; } private boolean hasNoViewer(List viewers) { @@ -170,16 +172,19 @@ public class SimpleStorageBlockEntity extends BlockEntity { return this.isValid() && this.inventory != null && this.behavior != null; } - public void updateOpenBlockState(boolean open) { + public ImmutableBlockState updateOpenBlockState(boolean open) { ImmutableBlockState state = super.world.getBlockStateAtIfLoaded(this.pos); - if (state == null || state.behavior() != this.behavior) return; + if (state == null || state.behavior() != this.behavior) return this.blockState; Property property = this.behavior.openProperty(); - if (property == null) return; - super.world.world().setBlockAt(this.pos.x(), this.pos.y(), this.pos.z(), state.with(property, open), UpdateOption.UPDATE_ALL.flags()); + if (property == null) return state; + state = state.with(property, open); + super.world.world().setBlockAt(this.pos.x(), this.pos.y(), this.pos.z(), state, UpdateOption.UPDATE_ALL.flags()); + return state; } public void checkOpeners(Object level, Object pos, Object blockState) { if (!this.isValidContainer()) return; + Object tickState = blockState; double maxInteractionDistance = 0d; List viewers = this.inventory.getViewers(); int validViewers = 0; @@ -193,14 +198,14 @@ public class SimpleStorageBlockEntity extends BlockEntity { } boolean shouldOpen = validViewers != 0; if (shouldOpen && !this.openState) { - this.setOpen(null); + tickState = this.setOpen(null).customBlockState().literalObject(); } else if (!shouldOpen && this.openState) { - this.setClose(null); + tickState = this.setClose(null).customBlockState().literalObject(); } this.maxInteractionDistance = maxInteractionDistance; if (!viewers.isEmpty()) { - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(blockState), 5); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(tickState), 5); } } From 09c60273be08b758b632f886c257f204f18c7551 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 19 Sep 2025 10:42:57 +0800 Subject: [PATCH 027/125] =?UTF-8?q?Revert=20"fix(block):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E9=94=99=E8=AF=AF=E7=9A=84tick=E6=96=B9=E5=9D=97?= =?UTF-8?q?=E6=96=B9=E5=BC=8F"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 1d500a580de7b39a5bbcf2945d813379e0b1aa88. --- .../block/behavior/ButtonBlockBehavior.java | 26 +++++++--------- .../behavior/PressurePlateBlockBehavior.java | 20 ++++++------ .../entity/SimpleStorageBlockEntity.java | 31 ++++++++----------- 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java index 7bca026c1..3be8fa890 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java @@ -53,7 +53,8 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { @Override public InteractionResult useWithoutItem(UseOnContext context, ImmutableBlockState state) { if (!state.get(this.poweredProperty)) { - press(state, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), + press(BlockStateUtils.getBlockOwner(state.customBlockState().literalObject()), + state, context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()), context.getPlayer() != null ? context.getPlayer().serverPlayer() : null); return InteractionResult.SUCCESS_AND_CANCEL; } @@ -65,7 +66,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(args[0]).orElse(null); if (blockState == null) return; if (FastNMS.INSTANCE.method$Explosion$canTriggerBlocks(args[3]) && !blockState.get(this.poweredProperty)) { - press(blockState, args[1], args[2], null); + press(thisBlock, blockState, args[1], args[2], null); } } @@ -116,7 +117,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); if (blockState == null) return; if (blockState.get(this.poweredProperty)) { - checkPressed(state, level, pos); + checkPressed(thisBlock, state, level, pos); } } @@ -128,12 +129,11 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); if (blockState == null) return; if (this.canButtonBeActivatedByArrows && !blockState.get(this.poweredProperty)) { - checkPressed(state, level, pos); + checkPressed(thisBlock, state, level, pos); } } - private void checkPressed(Object state, Object level, Object pos) { - Object tickState = state; + private void checkPressed(Object thisBlock, Object state, Object level, Object pos) { Object abstractArrow = this.canButtonBeActivatedByArrows ? FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass( level, CoreReflections.clazz$AbstractArrow, FastNMS.INSTANCE.method$AABB$move( FastNMS.INSTANCE.method$VoxelShape$bounds(FastNMS.INSTANCE.method$BlockState$getShape( @@ -144,9 +144,8 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { if (blockState == null) return; boolean poweredValue = blockState.get(this.poweredProperty); if (flag != poweredValue) { - tickState = blockState.with(this.poweredProperty, flag).customBlockState().literalObject(); - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, tickState, UpdateOption.UPDATE_ALL.flags()); - updateNeighbours(BlockStateUtils.getBlockOwner(tickState), blockState, level, pos); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, blockState.with(this.poweredProperty, flag).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); + updateNeighbours(thisBlock, blockState, level, pos); playSound(null, level, pos, flag); Object gameEvent = VersionHelper.isOrAbove1_20_5() ? FastNMS.INSTANCE.method$Holder$direct(flag ? MGameEvent.BLOCK_ACTIVATE : MGameEvent.BLOCK_DEACTIVATE) @@ -155,7 +154,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { } if (flag) { - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(tickState), this.ticksToStayPressed); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.ticksToStayPressed); } } @@ -189,10 +188,9 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { return isOn ? this.buttonClickOnSound : this.buttonClickOffSound; } - private void press(ImmutableBlockState state, Object level, Object pos, @Nullable Object player) { - Object tickState = state.with(this.poweredProperty, true).customBlockState().literalObject(); - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, tickState, UpdateOption.UPDATE_ALL.flags()); - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(tickState), this.ticksToStayPressed); + private void press(Object thisBlock, ImmutableBlockState state, Object level, Object pos, @Nullable Object player) { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, state.with(this.poweredProperty, true).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.ticksToStayPressed); playSound(player, level, pos, true); Object gameEvent = VersionHelper.isOrAbove1_20_5() ? FastNMS.INSTANCE.method$Holder$direct(MGameEvent.BLOCK_ACTIVATE) : MGameEvent.BLOCK_ACTIVATE; FastNMS.INSTANCE.method$LevelAccessor$gameEvent(level, player, gameEvent, pos); 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 a3e85d6ae..5ec5cc268 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 @@ -29,6 +29,7 @@ import javax.annotation.Nullable; import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; +import java.util.function.Predicate; public class PressurePlateBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); @@ -86,7 +87,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { Object state = args[0]; int signalForState = this.getSignalForState(state); if (signalForState > 0) { - this.checkPressed(null, args[1], args[2], state, signalForState); + this.checkPressed(null, args[1], args[2], state, signalForState, thisBlock); } } @@ -100,7 +101,9 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { Object state = args[0]; int signalForState = this.getSignalForState(state); if (signalForState == 0) { - this.checkPressed(args[3], args[1], args[2], state, signalForState); + this.checkPressed(args[3], args[1], args[2], state, signalForState, thisBlock); + } else { + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime); } } @@ -122,17 +125,16 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { return optionalCustomState.get().with(this.poweredProperty, strength > 0).customBlockState().literalObject(); } - private void checkPressed(@Nullable Object entity, Object level, Object pos, Object state, int currentSignal) { - Object tickState = state; + private void checkPressed(@Nullable Object entity, Object level, Object pos, Object state, int currentSignal, Object thisBlock) { int signalStrength = this.getSignalStrength(level, pos); boolean wasActive = currentSignal > 0; boolean isActive = signalStrength > 0; if (currentSignal != signalStrength) { - tickState = this.setSignalForState(state, signalStrength); - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, tickState, 2); - this.updateNeighbours(level, pos, BlockStateUtils.getBlockOwner(tickState)); - FastNMS.INSTANCE.method$Level$setBlocksDirty(level, pos, state, tickState); + Object blockState = this.setSignalForState(state, signalStrength); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, blockState, 2); + this.updateNeighbours(level, pos, thisBlock); + FastNMS.INSTANCE.method$Level$setBlocksDirty(level, pos, state, blockState); } org.bukkit.World craftWorld = FastNMS.INSTANCE.method$Level$getCraftWorld(level); @@ -148,7 +150,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { } if (isActive) { - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(tickState), this.pressedTime); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.pressedTime); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java index f889df503..fcb654c71 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/entity/SimpleStorageBlockEntity.java @@ -107,8 +107,8 @@ public class SimpleStorageBlockEntity extends BlockEntity { // 有非观察者的人,那么就不触发开启音效和事件 if (!hasNoViewer(this.inventory.getViewers())) return; this.maxInteractionDistance = Math.max(player.getCachedInteractionRange(), this.maxInteractionDistance); - ImmutableBlockState state = this.setOpen(player); - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(super.world.world().serverWorld(), LocationUtils.toBlockPos(this.pos), BlockStateUtils.getBlockOwner(state.customBlockState().literalObject()), 5); + this.setOpen(player); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(super.world.world().serverWorld(), LocationUtils.toBlockPos(this.pos), BlockStateUtils.getBlockOwner(this.blockState.customBlockState().literalObject()), 5); } } @@ -127,8 +127,8 @@ public class SimpleStorageBlockEntity extends BlockEntity { } } - private ImmutableBlockState setOpen(@Nullable Player player) { - ImmutableBlockState state = this.updateOpenBlockState(true); + private void setOpen(@Nullable Player player) { + this.updateOpenBlockState(true); org.bukkit.World bukkitWorld = (org.bukkit.World) super.world.world().platformWorld(); if (player != null) { bukkitWorld.sendGameEvent((org.bukkit.entity.Player) player.platformPlayer(), GameEvent.CONTAINER_OPEN, new Vector(this.pos.x(), this.pos.y(), this.pos.z())); @@ -140,11 +140,10 @@ public class SimpleStorageBlockEntity extends BlockEntity { if (soundData != null) { super.world.world().playBlockSound(Vec3d.atCenterOf(this.pos), soundData); } - return state; } - private ImmutableBlockState setClose(@Nullable Player player) { - ImmutableBlockState state = this.updateOpenBlockState(false); + private void setClose(@Nullable Player player) { + this.updateOpenBlockState(false); org.bukkit.World bukkitWorld = (org.bukkit.World) super.world.world().platformWorld(); if (player != null) { bukkitWorld.sendGameEvent((org.bukkit.entity.Player) player.platformPlayer(), GameEvent.CONTAINER_CLOSE, new Vector(this.pos.x(), this.pos.y(), this.pos.z())); @@ -156,7 +155,6 @@ public class SimpleStorageBlockEntity extends BlockEntity { if (soundData != null) { super.world.world().playBlockSound(Vec3d.atCenterOf(this.pos), soundData); } - return state; } private boolean hasNoViewer(List viewers) { @@ -172,19 +170,16 @@ public class SimpleStorageBlockEntity extends BlockEntity { return this.isValid() && this.inventory != null && this.behavior != null; } - public ImmutableBlockState updateOpenBlockState(boolean open) { + public void updateOpenBlockState(boolean open) { ImmutableBlockState state = super.world.getBlockStateAtIfLoaded(this.pos); - if (state == null || state.behavior() != this.behavior) return this.blockState; + if (state == null || state.behavior() != this.behavior) return; Property property = this.behavior.openProperty(); - if (property == null) return state; - state = state.with(property, open); - super.world.world().setBlockAt(this.pos.x(), this.pos.y(), this.pos.z(), state, UpdateOption.UPDATE_ALL.flags()); - return state; + if (property == null) return; + super.world.world().setBlockAt(this.pos.x(), this.pos.y(), this.pos.z(), state.with(property, open), UpdateOption.UPDATE_ALL.flags()); } public void checkOpeners(Object level, Object pos, Object blockState) { if (!this.isValidContainer()) return; - Object tickState = blockState; double maxInteractionDistance = 0d; List viewers = this.inventory.getViewers(); int validViewers = 0; @@ -198,14 +193,14 @@ public class SimpleStorageBlockEntity extends BlockEntity { } boolean shouldOpen = validViewers != 0; if (shouldOpen && !this.openState) { - tickState = this.setOpen(null).customBlockState().literalObject(); + this.setOpen(null); } else if (!shouldOpen && this.openState) { - tickState = this.setClose(null).customBlockState().literalObject(); + this.setClose(null); } this.maxInteractionDistance = maxInteractionDistance; if (!viewers.isEmpty()) { - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(tickState), 5); + FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, BlockStateUtils.getBlockOwner(blockState), 5); } } From 1ac958cf659124482837c2a6de225334720fd926 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 19 Sep 2025 10:48:08 +0800 Subject: [PATCH 028/125] =?UTF-8?q?fix(block):=20=E6=9B=B4=E5=A5=BD?= =?UTF-8?q?=E7=9A=84=E4=BF=AE=E5=A4=8D=E9=94=99=E8=AF=AF=E7=9A=84tick?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 之前的方法太麻烦了可能会导致一些第三方开发者不知道这个问题,通过修改匹配方式解决此问题 --- .../plugin/injector/BlockStateGenerator.java | 29 ++++++++++++++++--- .../reflection/minecraft/CoreReflections.java | 4 +++ 2 files changed, 29 insertions(+), 4 deletions(-) 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 825f90a50..4dee54943 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 @@ -12,6 +12,7 @@ import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.bind.annotation.AllArguments; import net.bytebuddy.implementation.bind.annotation.RuntimeType; +import net.bytebuddy.implementation.bind.annotation.SuperCall; import net.bytebuddy.implementation.bind.annotation.This; import net.bytebuddy.matcher.ElementMatchers; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; @@ -21,14 +22,15 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlockStateProperties; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MLootContextParams; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; -import net.momirealms.craftengine.core.block.BlockSettings; -import net.momirealms.craftengine.core.block.DelegatingBlockState; -import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.util.ObjectHolder; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.World; @@ -39,6 +41,8 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.List; +import java.util.Optional; +import java.util.concurrent.Callable; public final class BlockStateGenerator { private static MethodHandle constructor$CraftEngineBlockState; @@ -64,7 +68,9 @@ public final class BlockStateGenerator { .method(ElementMatchers.is(CoreReflections.method$StateHolder$getValue)) .intercept(MethodDelegation.to(GetPropertyValueInterceptor.INSTANCE)) .method(ElementMatchers.is(CoreReflections.method$StateHolder$setValue)) - .intercept(MethodDelegation.to(SetPropertyValueInterceptor.INSTANCE)); + .intercept(MethodDelegation.to(SetPropertyValueInterceptor.INSTANCE)) + .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isBlock)) + .intercept(MethodDelegation.to(IsBlockInterceptor.INSTANCE)); Class clazz$CraftEngineBlock = stateBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded(); constructor$CraftEngineBlockState = VersionHelper.isOrAbove1_20_5() ? MethodHandles.publicLookup().in(clazz$CraftEngineBlock) @@ -183,6 +189,21 @@ public final class BlockStateGenerator { } } + public static class IsBlockInterceptor { + public static final IsBlockInterceptor INSTANCE = new IsBlockInterceptor(); + + @RuntimeType + public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { + DelegatingBlockState customState = (DelegatingBlockState) thisObj; + ImmutableBlockState thisState = customState.blockState(); + if (thisState == null) return false; + if (!(args[0] instanceof DelegatingBlock delegatingBlock)) return false; + BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); + if (behavior == null) return false; + return behavior.equals(thisState.owner().value()); + } + } + public static class CreateStateInterceptor { public static final CreateStateInterceptor INSTANCE = new CreateStateInterceptor(); 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 4fb178606..e3eded271 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 @@ -4406,4 +4406,8 @@ public final class CoreReflections { BukkitReflectionUtils.assembleMCClass("world.level.gameevent.GameEvent") ) ); + + public static final Method method$BlockStateBase$isBlock = requireNonNull( + ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Block) + ); } From ecab22cc9b0a85d85b28a14a545a8b98d411fa24 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 19 Sep 2025 11:24:08 +0800 Subject: [PATCH 029/125] =?UTF-8?q?feat(block):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../behavior/PressurePlateBlockBehavior.java | 2 - .../plugin/injector/BlockStateGenerator.java | 74 ++++++++++++++++++- .../reflection/minecraft/CoreReflections.java | 22 ++++++ 3 files changed, 94 insertions(+), 4 deletions(-) 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 5ec5cc268..0453403b5 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 @@ -102,8 +102,6 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { int signalForState = this.getSignalForState(state); if (signalForState == 0) { this.checkPressed(args[3], args[1], args[2], state, signalForState, thisBlock); - } else { - FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(args[1], args[2], thisBlock, this.pressedTime); } } 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 4dee54943..9281595d8 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 @@ -20,6 +20,7 @@ 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.MBlockStateProperties; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MLootContextParams; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -70,7 +71,19 @@ public final class BlockStateGenerator { .method(ElementMatchers.is(CoreReflections.method$StateHolder$setValue)) .intercept(MethodDelegation.to(SetPropertyValueInterceptor.INSTANCE)) .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isBlock)) - .intercept(MethodDelegation.to(IsBlockInterceptor.INSTANCE)); + .intercept(MethodDelegation.to(IsBlockInterceptor.INSTANCE)) + .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isHolderSetBlock)) + .intercept(MethodDelegation.to(IsHolderSetBlockInterceptor.INSTANCE)); + if (CoreReflections.method$BlockStateBase$isHolderBlock != null) { + stateBuilder = stateBuilder + .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isHolderBlock)) + .intercept(MethodDelegation.to(IsHolderBlockInterceptor.INSTANCE)); + } + if (CoreReflections.method$BlockStateBase$isResourceKeyBlock != null) { + stateBuilder = stateBuilder + .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isResourceKeyBlock)) + .intercept(MethodDelegation.to(IsResourceKeyBlockInterceptor.INSTANCE)); + } Class clazz$CraftEngineBlock = stateBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded(); constructor$CraftEngineBlockState = VersionHelper.isOrAbove1_20_5() ? MethodHandles.publicLookup().in(clazz$CraftEngineBlock) @@ -200,7 +213,64 @@ public final class BlockStateGenerator { if (!(args[0] instanceof DelegatingBlock delegatingBlock)) return false; BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); if (behavior == null) return false; - return behavior.equals(thisState.owner().value()); + return behavior.block().equals(thisState.owner().value()); + } + } + + public static class IsHolderSetBlockInterceptor { + public static final IsHolderSetBlockInterceptor INSTANCE = new IsHolderSetBlockInterceptor(); + + @SuppressWarnings("unchecked") + @RuntimeType + public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { + DelegatingBlockState customState = (DelegatingBlockState) thisObj; + ImmutableBlockState thisState = customState.blockState(); + if (thisState == null) return false; + CustomBlock thisBlock = thisState.owner().value(); + for (Object holder : (Iterable) args[0]) { + Object block = FastNMS.INSTANCE.method$Holder$value(holder); + if (!(block instanceof DelegatingBlock delegatingBlock)) continue; + BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); + if (behavior == null) continue; + if (behavior.block().equals(thisBlock)) return true; + } + return false; + } + } + + public static class IsHolderBlockInterceptor { + public static final IsHolderBlockInterceptor INSTANCE = new IsHolderBlockInterceptor(); + + @RuntimeType + public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { + DelegatingBlockState customState = (DelegatingBlockState) thisObj; + ImmutableBlockState thisState = customState.blockState(); + if (thisState == null) return false; + CustomBlock thisBlock = thisState.owner().value(); + Object block = FastNMS.INSTANCE.method$Holder$value(args[0]); + if (!(block instanceof DelegatingBlock delegatingBlock)) return false; + BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); + if (behavior == null) return false; + return behavior.block().equals(thisBlock); + } + } + + public static class IsResourceKeyBlockInterceptor { + public static final IsResourceKeyBlockInterceptor INSTANCE = new IsResourceKeyBlockInterceptor(); + + @RuntimeType + public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { + DelegatingBlockState customState = (DelegatingBlockState) thisObj; + ImmutableBlockState thisState = customState.blockState(); + if (thisState == null) return false; + CustomBlock thisBlock = thisState.owner().value(); + Object block = FastNMS.INSTANCE.method$HolderGetter$getResourceKey(MBuiltInRegistries.BLOCK, args[0]) + .map(FastNMS.INSTANCE::method$Holder$value) + .orElse(null); + if (!(block instanceof DelegatingBlock delegatingBlock)) return false; + BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); + if (behavior == null) return false; + return behavior.block().equals(thisBlock); } } 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 e3eded271..571f99f4a 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 @@ -4407,7 +4407,29 @@ public final class CoreReflections { ) ); + public static final Class clazz$HolderSet = requireNonNull( + ReflectionUtils.getClazz( + BukkitReflectionUtils.assembleMCClass("core.HolderSet") + ) + ); + public static final Method method$BlockStateBase$isBlock = requireNonNull( ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Block) ); + + public static final Method method$BlockStateBase$isHolderSetBlock = requireNonNull( + ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$HolderSet) + ); + + // 1.20.2+ + public static final Method method$BlockStateBase$isHolderBlock = MiscUtils.requireNonNullIf( + ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Holder), + VersionHelper.isOrAbove1_20_2() + ); + + // 1.20.3+ + public static final Method method$BlockStateBase$isResourceKeyBlock = MiscUtils.requireNonNullIf( + ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$ResourceKey), + VersionHelper.isOrAbove1_20_3() + ); } From 3e15a6bbc2eb360658abc78a1cbc3ba1aa3187d8 Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <972454774@qq.com> Date: Fri, 19 Sep 2025 15:26:33 +0800 Subject: [PATCH 030/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dimage=E8=A7=A3?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/config.yml | 2 ++ .../core/pack/cache/AutoIdCache.java | 27 +++++++++++++++++++ .../core/plugin/config/Config.java | 7 +++++ .../context/function/ActionBarFunction.java | 14 +++++----- .../context/function/MessageFunction.java | 16 +++++------ .../context/function/OpenWindowFunction.java | 12 ++++----- .../context/function/TitleFunction.java | 19 ++++++------- gradle.properties | 2 +- 8 files changed, 63 insertions(+), 36 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoIdCache.java diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index c69bf57ba..22cbd0dad 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -163,6 +163,8 @@ equipment: humanoid-leggings: minecraft:trims/entity/humanoid_leggings/chainmail block: + # This decides the amount of real blocks on serverside. Requires a restart to apply. + serverside-blocks: 2000 # Enables the sound system, which prevents the client from hearing some non-custom block sounds and improves the client experience. sound-system: enable: true diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoIdCache.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoIdCache.java new file mode 100644 index 000000000..1588a2d1b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoIdCache.java @@ -0,0 +1,27 @@ +package net.momirealms.craftengine.core.pack.cache; + +import java.util.BitSet; +import java.util.HashMap; +import java.util.Map; + +public class AutoIdCache { + private final Map forcedIds = new HashMap<>(); + private final Map cachedIds = new HashMap<>(); + private final BitSet occupiedIds = new BitSet(); + private int currentAutoId; + + public AutoIdCache(int startIndex) { + this.currentAutoId = startIndex; + } + + public boolean setForcedId(final String name, int index) { + if (this.occupiedIds.get(index)) { + return false; + } + this.occupiedIds.set(index); + this.forcedIds.put(name, index); + return true; + } + + +} 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 834947120..65681858e 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 @@ -123,6 +123,7 @@ public class Config { protected int block$predict_breaking_interval; protected double block$extended_interaction_range; protected boolean block$chunk_relighter; + protected int block$serverside_blocks; protected boolean recipe$enable; protected boolean recipe$disable_vanilla_recipes$all; @@ -134,6 +135,7 @@ public class Config { protected boolean image$illegal_characters_filter$anvil; protected boolean image$illegal_characters_filter$sign; protected boolean image$illegal_characters_filter$book; + protected boolean network$intercept_packets$system_chat; protected boolean network$intercept_packets$tab_list; protected boolean network$intercept_packets$actionbar; @@ -392,6 +394,7 @@ public class Config { block$predict_breaking_interval = Math.max(config.getInt("block.predict-breaking.interval", 10), 1); block$extended_interaction_range = Math.max(config.getDouble("block.predict-breaking.extended-interaction-range", 0.5), 0.0); block$chunk_relighter = config.getBoolean("block.chunk-relighter", true); + block$serverside_blocks = config.getInt("block.serverside-blocks", 2000); // recipe recipe$enable = config.getBoolean("recipe.enable", true); @@ -478,6 +481,10 @@ public class Config { return instance.metrics; } + public static int serverSideBlocks() { + return instance.block$serverside_blocks; + } + public static boolean filterConfigurationPhaseDisconnect() { return instance.filterConfigurationPhaseDisconnect; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java index 86aeebfa5..bcd5041cb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/ActionBarFunction.java @@ -5,8 +5,6 @@ import net.momirealms.craftengine.core.plugin.context.*; 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.plugin.context.text.TextProvider; -import net.momirealms.craftengine.core.plugin.context.text.TextProviders; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -16,12 +14,12 @@ import java.util.List; import java.util.Map; public class ActionBarFunction extends AbstractConditionalFunction { - private final TextProvider message; + private final String message; private final PlayerSelector selector; - public ActionBarFunction(List> predicates, @Nullable PlayerSelector selector, TextProvider messages) { + public ActionBarFunction(List> predicates, @Nullable PlayerSelector selector, String message) { super(predicates); - this.message = messages; + this.message = message; this.selector = selector; } @@ -29,12 +27,12 @@ public class ActionBarFunction extends AbstractConditionalF public void runInternal(CTX ctx) { if (this.selector == null) { ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { - it.sendActionBar(AdventureHelper.miniMessage().deserialize(this.message.get(ctx), ctx.tagResolvers())); + it.sendActionBar(AdventureHelper.miniMessage().deserialize(this.message, ctx.tagResolvers())); }); } else { for (Player viewer : this.selector.get(ctx)) { RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer)); - viewer.sendActionBar(AdventureHelper.miniMessage().deserialize(this.message.get(relationalContext), relationalContext.tagResolvers())); + viewer.sendActionBar(AdventureHelper.miniMessage().deserialize(this.message, relationalContext.tagResolvers())); } } } @@ -53,7 +51,7 @@ public class ActionBarFunction extends AbstractConditionalF @Override public Function create(Map arguments) { String message = ResourceConfigUtils.requireNonEmptyStringOrThrow(ResourceConfigUtils.get(arguments, "actionbar", "message"), "warning.config.function.actionbar.missing_actionbar"); - return new ActionBarFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), TextProviders.fromString(message)); + return new ActionBarFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), message); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java index ffedc3333..c69d3663e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/MessageFunction.java @@ -5,8 +5,6 @@ import net.momirealms.craftengine.core.plugin.context.*; 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.plugin.context.text.TextProvider; -import net.momirealms.craftengine.core.plugin.context.text.TextProviders; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -17,11 +15,11 @@ import java.util.List; import java.util.Map; public class MessageFunction extends AbstractConditionalFunction { - private final List messages; + private final List messages; private final PlayerSelector selector; private final boolean overlay; - public MessageFunction(List> predicates, @Nullable PlayerSelector selector, List messages, boolean overlay) { + public MessageFunction(List> predicates, @Nullable PlayerSelector selector, List messages, boolean overlay) { super(predicates); this.messages = messages; this.selector = selector; @@ -32,15 +30,15 @@ public class MessageFunction extends AbstractConditionalFun public void runInternal(CTX ctx) { if (this.selector == null) { ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { - for (TextProvider c : this.messages) { - it.sendMessage(AdventureHelper.miniMessage().deserialize(c.get(ctx), ctx.tagResolvers()), this.overlay); + for (String c : this.messages) { + it.sendMessage(AdventureHelper.miniMessage().deserialize(c, ctx.tagResolvers()), this.overlay); } }); } else { for (Player viewer : this.selector.get(ctx)) { RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer)); - for (TextProvider c : this.messages) { - viewer.sendMessage(AdventureHelper.miniMessage().deserialize(c.get(relationalContext), relationalContext.tagResolvers()), this.overlay); + for (String c : this.messages) { + viewer.sendMessage(AdventureHelper.miniMessage().deserialize(c, relationalContext.tagResolvers()), this.overlay); } } } @@ -60,7 +58,7 @@ public class MessageFunction extends AbstractConditionalFun @Override public Function create(Map arguments) { Object message = ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(arguments, "messages", "message"), "warning.config.function.command.missing_message"); - List messages = MiscUtils.getAsStringList(message).stream().map(TextProviders::fromString).toList(); + List messages = MiscUtils.getAsStringList(message); boolean overlay = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("overlay", false), "overlay"); return new MessageFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), messages, overlay); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java index 3cda10b9b..bbe2fe3d0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/OpenWindowFunction.java @@ -6,8 +6,6 @@ import net.momirealms.craftengine.core.plugin.context.*; 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.plugin.context.text.TextProvider; -import net.momirealms.craftengine.core.plugin.context.text.TextProviders; import net.momirealms.craftengine.core.plugin.gui.GuiType; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.AdventureHelper; @@ -24,9 +22,9 @@ import java.util.Optional; public class OpenWindowFunction extends AbstractConditionalFunction { private final PlayerSelector selector; private final GuiType guiType; - private final TextProvider optionalTitle; + private final String optionalTitle; - public OpenWindowFunction(List> predicates, @Nullable PlayerSelector selector, GuiType guiType, TextProvider optionalTitle) { + public OpenWindowFunction(List> predicates, @Nullable PlayerSelector selector, GuiType guiType, String optionalTitle) { super(predicates); this.selector = selector; this.guiType = guiType; @@ -39,7 +37,7 @@ public class OpenWindowFunction extends AbstractConditional ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> { CraftEngine.instance().guiManager().openInventory(it, this.guiType); if (this.optionalTitle != null) { - CraftEngine.instance().guiManager().updateInventoryTitle(it, AdventureHelper.miniMessage().deserialize(this.optionalTitle.get(ctx), ctx.tagResolvers())); + CraftEngine.instance().guiManager().updateInventoryTitle(it, AdventureHelper.miniMessage().deserialize(this.optionalTitle, ctx.tagResolvers())); } }); } else { @@ -47,7 +45,7 @@ public class OpenWindowFunction extends AbstractConditional CraftEngine.instance().guiManager().openInventory(viewer, this.guiType); if (this.optionalTitle != null) { RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer)); - CraftEngine.instance().guiManager().updateInventoryTitle(viewer, AdventureHelper.miniMessage().deserialize(this.optionalTitle.get(relationalContext), relationalContext.tagResolvers())); + CraftEngine.instance().guiManager().updateInventoryTitle(viewer, AdventureHelper.miniMessage().deserialize(this.optionalTitle, relationalContext.tagResolvers())); } } } @@ -66,7 +64,7 @@ public class OpenWindowFunction extends AbstractConditional @Override public Function create(Map arguments) { - TextProvider title = Optional.ofNullable(arguments.get("title")).map(String::valueOf).map(TextProviders::fromString).orElse(null); + String title = Optional.ofNullable(arguments.get("title")).map(String::valueOf).orElse(null); String rawType = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("gui-type"), "warning.config.function.open_window.missing_gui_type"); try { GuiType type = GuiType.valueOf(rawType.toUpperCase(Locale.ENGLISH)); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java index cbae62005..97a56b443 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/TitleFunction.java @@ -7,8 +7,6 @@ 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.plugin.context.text.TextProvider; -import net.momirealms.craftengine.core.plugin.context.text.TextProviders; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; @@ -18,14 +16,14 @@ import java.util.Map; public class TitleFunction extends AbstractConditionalFunction { private final PlayerSelector selector; - private final TextProvider main; - private final TextProvider sub; + private final String main; + private final String sub; private final NumberProvider fadeIn; private final NumberProvider stay; private final NumberProvider fadeOut; public TitleFunction(List> predicates, @Nullable PlayerSelector selector, - TextProvider main, TextProvider sub, NumberProvider fadeIn, NumberProvider stay, NumberProvider fadeOut) { + String main, String sub, NumberProvider fadeIn, NumberProvider stay, NumberProvider fadeOut) { super(predicates); this.selector = selector; this.main = main; @@ -39,16 +37,16 @@ public class TitleFunction extends AbstractConditionalFunct public void runInternal(CTX ctx) { if (this.selector == null) { ctx.getOptionalParameter(DirectContextParameters.PLAYER).ifPresent(it -> it.sendTitle( - AdventureHelper.miniMessage().deserialize(this.main.get(ctx), ctx.tagResolvers()), - AdventureHelper.miniMessage().deserialize(this.sub.get(ctx), ctx.tagResolvers()), + AdventureHelper.miniMessage().deserialize(this.main, ctx.tagResolvers()), + AdventureHelper.miniMessage().deserialize(this.sub, ctx.tagResolvers()), this.fadeIn.getInt(ctx), this.stay.getInt(ctx), this.fadeOut.getInt(ctx) )); } else { for (Player viewer : this.selector.get(ctx)) { RelationalContext relationalContext = ViewerContext.of(ctx, PlayerOptionalContext.of(viewer)); viewer.sendTitle( - AdventureHelper.miniMessage().deserialize(this.main.get(relationalContext), relationalContext.tagResolvers()), - AdventureHelper.miniMessage().deserialize(this.sub.get(relationalContext), relationalContext.tagResolvers()), + AdventureHelper.miniMessage().deserialize(this.main, relationalContext.tagResolvers()), + AdventureHelper.miniMessage().deserialize(this.sub, relationalContext.tagResolvers()), this.fadeIn.getInt(relationalContext), this.stay.getInt(relationalContext), this.fadeOut.getInt(relationalContext) ); } @@ -73,8 +71,7 @@ public class TitleFunction extends AbstractConditionalFunct NumberProvider fadeIn = NumberProviders.fromObject(arguments.getOrDefault("fade-in", 10)); NumberProvider stay = NumberProviders.fromObject(arguments.getOrDefault("stay", 20)); NumberProvider fadeOut = NumberProviders.fromObject(arguments.getOrDefault("fade-out", 5)); - return new TitleFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), - TextProviders.fromString(title), TextProviders.fromString(subtitle), fadeIn, stay, fadeOut); + return new TitleFunction<>(getPredicates(arguments), PlayerSelectors.fromObject(arguments.get("target"), conditionFactory()), title, subtitle, fadeIn, stay, fadeOut); } } } diff --git a/gradle.properties b/gradle.properties index e6e8440a9..1aab59f11 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.3 +project_version=0.0.63.4 config_version=46 lang_version=30 project_group=net.momirealms From 71f75d5d16152087682197140bfeaf76246579a5 Mon Sep 17 00:00:00 2001 From: Xiao-MoMi <972454774@qq.com> Date: Fri, 19 Sep 2025 20:39:22 +0800 Subject: [PATCH 031/125] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=BC=B9=E5=B0=84?= =?UTF-8?q?=E7=89=A9=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/entity/projectile/ProjectileMeta.java | 4 +--- .../craftengine/core/entity/projectile/ProjectileType.java | 5 ----- .../net/momirealms/craftengine/core/item/ItemSettings.java | 4 +--- 3 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileType.java diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java index 4dbefc9b4..7801b8f9d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileMeta.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.entity.projectile; import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.util.Key; -import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; @@ -13,6 +12,5 @@ public record ProjectileMeta(Key item, Vector3f scale, Vector3f translation, Quaternionf rotation, - double range, - @Nullable ProjectileType type) { + double range) { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileType.java b/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileType.java deleted file mode 100644 index 0c0e1d5ed..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/projectile/ProjectileType.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.momirealms.craftengine.core.entity.projectile; - -public enum ProjectileType { - TRIDENT -} 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 03c355356..076316376 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemSettings.java @@ -3,7 +3,6 @@ package net.momirealms.craftengine.core.item; 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; @@ -408,9 +407,8 @@ public class ItemSettings { Vector3f translation = ResourceConfigUtils.getAsVector3f(args.getOrDefault("translation", "0"), "translation"); Vector3f scale = ResourceConfigUtils.getAsVector3f(args.getOrDefault("scale", "1"), "scale"); Quaternionf rotation = ResourceConfigUtils.getAsQuaternionf(ResourceConfigUtils.get(args, "rotation"), "rotation"); - ProjectileType type = Optional.ofNullable(args.get("type")).map(String::valueOf).map(it -> ProjectileType.valueOf(it.toUpperCase(Locale.ENGLISH))).orElse(null); double range = ResourceConfigUtils.getAsDouble(args.getOrDefault("range", 1), "range"); - return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, billboard, scale, translation, rotation, range, type)); + return settings -> settings.projectileMeta(new ProjectileMeta(customTridentItemId, displayType, billboard, scale, translation, rotation, range)); })); registerFactory("helmet", (value -> { Map args = MiscUtils.castToMap(value, false); From 3ec61174180088f1379b2bd3b7651dbe6a6ea86f Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 19 Sep 2025 23:33:16 +0800 Subject: [PATCH 032/125] =?UTF-8?q?fix(compatibility):=20=E6=94=B9?= =?UTF-8?q?=E8=BF=9B=E4=B8=80=E4=B8=AA=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/compatibility/BukkitCompatibilityManager.java | 4 ++++ 1 file changed, 4 insertions(+) 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 c4ca0328e..8e4f5785e 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 @@ -20,6 +20,7 @@ import net.momirealms.craftengine.bukkit.compatibility.worldedit.WorldEditBlockR import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.entity.furniture.ExternalModel; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.loot.LootConditions; @@ -32,6 +33,7 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldManager; import org.bukkit.Bukkit; +import org.bukkit.Registry; import org.bukkit.plugin.Plugin; import java.util.*; @@ -250,6 +252,8 @@ public class BukkitCompatibilityManager implements CompatibilityManager { weBlockRegister.register(newBlockId); } } catch (Exception e) { + // 检查是不是有插件干预了注册表 + if (Registry.MATERIAL.get(KeyUtils.toNamespacedKey(BukkitBlockManager.instance().blockRegisterOrder().getFirst())) != null) return; this.plugin.logger().warn("Failed to initialize world edit hook", e); } } From 51a641ed91fd6f2f9e4903464bd6461e7b623a23 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Sat, 20 Sep 2025 02:18:05 +0800 Subject: [PATCH 033/125] =?UTF-8?q?fix(network):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E4=B8=80=E4=B8=AA=E9=94=99=E8=AF=AF=E7=9A=84=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=88=A4=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/handler/MinecartPacketHandler.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java index 718946298..ff4c81023 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java @@ -25,7 +25,7 @@ import java.util.Optional; public class MinecartPacketHandler implements EntityPacketHandler { public static final MinecartPacketHandler INSTANCE = new MinecartPacketHandler(); - private static final BlockStateHandler BLOCK_STATE_HANDLER = VersionHelper.isOrAbove1_21_3() ? BlockStateHandler_1_21_3.INSTANCE : BlockStateHandler_1_20.INSTANCE; + private static final BlockStateHandler BLOCK_STATE_HANDLER = VersionHelper.isOrAbove1_21_5() ? BlockStateHandler_1_21_5.INSTANCE : BlockStateHandler_1_20.INSTANCE; @Override public void handleSetEntityData(Player user, ByteBufPacketEvent event) { @@ -69,8 +69,8 @@ public class MinecartPacketHandler implements EntityPacketHandler { Object handle(NetWorkUser user, Object packedItem, int entityDataId); } - static class BlockStateHandler_1_21_3 implements BlockStateHandler { - protected static final BlockStateHandler INSTANCE = new BlockStateHandler_1_21_3(); + static class BlockStateHandler_1_21_5 implements BlockStateHandler { + protected static final BlockStateHandler INSTANCE = new BlockStateHandler_1_21_5(); @Override public Object handle(NetWorkUser user, Object packedItem, int entityDataId) { From 862203ca2a730d31010cdfeec20651ecb3c151b8 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Sat, 20 Sep 2025 02:32:12 +0800 Subject: [PATCH 034/125] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BukkitCompatibilityManager.java | 4 ---- .../plugin/injector/BlockStateGenerator.java | 16 ++++++++-------- 2 files changed, 8 insertions(+), 12 deletions(-) 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 8e4f5785e..c4ca0328e 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 @@ -20,7 +20,6 @@ import net.momirealms.craftengine.bukkit.compatibility.worldedit.WorldEditBlockR import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.core.entity.furniture.ExternalModel; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.loot.LootConditions; @@ -33,7 +32,6 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldManager; import org.bukkit.Bukkit; -import org.bukkit.Registry; import org.bukkit.plugin.Plugin; import java.util.*; @@ -252,8 +250,6 @@ public class BukkitCompatibilityManager implements CompatibilityManager { weBlockRegister.register(newBlockId); } } catch (Exception e) { - // 检查是不是有插件干预了注册表 - if (Registry.MATERIAL.get(KeyUtils.toNamespacedKey(BukkitBlockManager.instance().blockRegisterOrder().getFirst())) != null) return; this.plugin.logger().warn("Failed to initialize world edit hook", 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 9281595d8..148fa9e3d 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 @@ -243,14 +243,14 @@ public final class BlockStateGenerator { @RuntimeType public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - DelegatingBlockState customState = (DelegatingBlockState) thisObj; - ImmutableBlockState thisState = customState.blockState(); - if (thisState == null) return false; - CustomBlock thisBlock = thisState.owner().value(); Object block = FastNMS.INSTANCE.method$Holder$value(args[0]); if (!(block instanceof DelegatingBlock delegatingBlock)) return false; BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); if (behavior == null) return false; + DelegatingBlockState customState = (DelegatingBlockState) thisObj; + ImmutableBlockState thisState = customState.blockState(); + if (thisState == null) return false; + CustomBlock thisBlock = thisState.owner().value(); return behavior.block().equals(thisBlock); } } @@ -260,16 +260,16 @@ public final class BlockStateGenerator { @RuntimeType public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - DelegatingBlockState customState = (DelegatingBlockState) thisObj; - ImmutableBlockState thisState = customState.blockState(); - if (thisState == null) return false; - CustomBlock thisBlock = thisState.owner().value(); Object block = FastNMS.INSTANCE.method$HolderGetter$getResourceKey(MBuiltInRegistries.BLOCK, args[0]) .map(FastNMS.INSTANCE::method$Holder$value) .orElse(null); if (!(block instanceof DelegatingBlock delegatingBlock)) return false; BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); if (behavior == null) return false; + DelegatingBlockState customState = (DelegatingBlockState) thisObj; + ImmutableBlockState thisState = customState.blockState(); + if (thisState == null) return false; + CustomBlock thisBlock = thisState.owner().value(); return behavior.block().equals(thisBlock); } } From ea1b684982dd803d7c35d5208df84baf2478c4a1 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Sat, 20 Sep 2025 02:35:21 +0800 Subject: [PATCH 035/125] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/ButtonBlockBehavior.java | 12 ++++++------ .../block/behavior/PressurePlateBlockBehavior.java | 5 ++--- .../{MEntitySelector.java => MEntitySelectors.java} | 4 ++-- .../minecraft/{MGameEvent.java => MGameEvents.java} | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/{MEntitySelector.java => MEntitySelectors.java} (80%) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/{MGameEvent.java => MGameEvents.java} (89%) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java index 3be8fa890..afa85f737 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java @@ -2,8 +2,8 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntitySelector; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MGameEvent; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntitySelectors; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MGameEvents; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.KeyUtils; @@ -138,7 +138,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { level, CoreReflections.clazz$AbstractArrow, FastNMS.INSTANCE.method$AABB$move( FastNMS.INSTANCE.method$VoxelShape$bounds(FastNMS.INSTANCE.method$BlockState$getShape( state, level, pos, CoreReflections.instance$CollisionContext$empty - )), pos), MEntitySelector.NO_SPECTATORS).stream().findFirst().orElse(null) : null; + )), pos), MEntitySelectors.NO_SPECTATORS).stream().findFirst().orElse(null) : null; boolean flag = abstractArrow != null; ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); if (blockState == null) return; @@ -148,8 +148,8 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { updateNeighbours(thisBlock, blockState, level, pos); playSound(null, level, pos, flag); Object gameEvent = VersionHelper.isOrAbove1_20_5() - ? FastNMS.INSTANCE.method$Holder$direct(flag ? MGameEvent.BLOCK_ACTIVATE : MGameEvent.BLOCK_DEACTIVATE) - : flag ? MGameEvent.BLOCK_ACTIVATE : MGameEvent.BLOCK_DEACTIVATE; + ? FastNMS.INSTANCE.method$Holder$direct(flag ? MGameEvents.BLOCK_ACTIVATE : MGameEvents.BLOCK_DEACTIVATE) + : flag ? MGameEvents.BLOCK_ACTIVATE : MGameEvents.BLOCK_DEACTIVATE; FastNMS.INSTANCE.method$LevelAccessor$gameEvent(level, abstractArrow, gameEvent, pos); } @@ -192,7 +192,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, state.with(this.poweredProperty, true).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.ticksToStayPressed); playSound(player, level, pos, true); - Object gameEvent = VersionHelper.isOrAbove1_20_5() ? FastNMS.INSTANCE.method$Holder$direct(MGameEvent.BLOCK_ACTIVATE) : MGameEvent.BLOCK_ACTIVATE; + Object gameEvent = VersionHelper.isOrAbove1_20_5() ? FastNMS.INSTANCE.method$Holder$direct(MGameEvents.BLOCK_ACTIVATE) : MGameEvents.BLOCK_ACTIVATE; FastNMS.INSTANCE.method$LevelAccessor$gameEvent(level, player, gameEvent, pos); } 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 0453403b5..3d8263e77 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 @@ -4,7 +4,7 @@ import io.papermc.paper.event.entity.EntityInsideBlockEvent; 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.plugin.reflection.minecraft.MEntitySelector; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntitySelectors; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.DirectionUtils; import net.momirealms.craftengine.bukkit.util.EventUtils; @@ -29,7 +29,6 @@ import javax.annotation.Nullable; import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; -import java.util.function.Predicate; public class PressurePlateBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); @@ -113,7 +112,7 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { Object box = FastNMS.INSTANCE.method$AABB$move(CoreReflections.instance$BasePressurePlateBlock$TOUCH_AABB, pos); return !FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass( level, clazz, box, - MEntitySelector.NO_SPECTATORS.and(entity -> !FastNMS.INSTANCE.method$Entity$isIgnoringBlockTriggers(entity)) + MEntitySelectors.NO_SPECTATORS.and(entity -> !FastNMS.INSTANCE.method$Entity$isIgnoringBlockTriggers(entity)) ).isEmpty() ? 15 : 0; } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelector.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelectors.java similarity index 80% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelector.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelectors.java index 7a2b43ab7..76bbaf19b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelector.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MEntitySelectors.java @@ -4,8 +4,8 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import java.util.function.Predicate; -public final class MEntitySelector { - private MEntitySelector() {} +public final class MEntitySelectors { + private MEntitySelectors() {} public static final Predicate NO_SPECTATORS = entity -> !FastNMS.INSTANCE.method$Entity$isSpectator(entity); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvent.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvents.java similarity index 89% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvent.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvents.java index 500f39d8c..fad931574 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvent.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MGameEvents.java @@ -2,8 +2,8 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import net.momirealms.craftengine.bukkit.nms.FastNMS; -public final class MGameEvent { - private MGameEvent() {} +public final class MGameEvents { + private MGameEvents() {} public static final Object BLOCK_ACTIVATE = getById("block_activate"); public static final Object BLOCK_DEACTIVATE = getById("block_deactivate"); From 150444819c9df01ee1eafcf757d14af8c30d69f7 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Sat, 20 Sep 2025 02:46:42 +0800 Subject: [PATCH 036/125] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...hedHorizontalDirectionalBlockBehavior.java | 20 +++++++++---------- .../src/main/resources/translations/en.yml | 3 +++ .../src/main/resources/translations/zh_cn.yml | 3 +++ .../core/block/properties/Properties.java | 4 ++-- .../{AttachFace.java => AnchorType.java} | 2 +- 5 files changed, 19 insertions(+), 13 deletions(-) rename core/src/main/java/net/momirealms/craftengine/core/block/state/properties/{AttachFace.java => AnchorType.java} (80%) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java index cc877ef06..597470895 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java @@ -11,7 +11,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.block.state.properties.AttachFace; +import net.momirealms.craftengine.core.block.state.properties.AnchorType; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.HorizontalDirection; @@ -27,7 +27,7 @@ import java.util.concurrent.Callable; public class FaceAttachedHorizontalDirectionalBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); - private final Property attachFaceProperty; + private final Property anchorTypeProperty; private final Property facingProperty; private final List tagsCanSurviveOn; private final Set blockStatesCanSurviveOn; @@ -39,14 +39,14 @@ public class FaceAttachedHorizontalDirectionalBlockBehavior extends BukkitBlockB List tagsCanSurviveOn, Set blockStatesCanSurviveOn, Set customBlocksCansSurviveOn, - Property attachFace, + Property anchorType, Property facing) { super(customBlock); this.tagsCanSurviveOn = tagsCanSurviveOn; this.blockStatesCanSurviveOn = blockStatesCanSurviveOn; this.customBlocksCansSurviveOn = customBlocksCansSurviveOn; this.blacklistMode = blacklist; - this.attachFaceProperty = attachFace; + this.anchorTypeProperty = anchorType; this.facingProperty = facing; } @@ -64,16 +64,16 @@ public class FaceAttachedHorizontalDirectionalBlockBehavior extends BukkitBlockB @SuppressWarnings("unchecked") @Override public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { - Property face = (Property) state.owner().value().getProperty("face"); + Property face = (Property) state.owner().value().getProperty("face"); Property facing = (Property) state.owner().value().getProperty("facing"); if (face == null || facing == null) return null; for (Direction direction : context.getNearestLookingDirections()) { if (direction.axis() == Direction.Axis.Y) { state = state - .with(face, direction == Direction.UP ? AttachFace.CEILING : AttachFace.FLOOR) + .with(face, direction == Direction.UP ? AnchorType.CEILING : AnchorType.FLOOR) .with(facing, context.getHorizontalDirection().toHorizontalDirection()); } else { - state = state.with(face, AttachFace.WALL).with(facing, direction.opposite().toHorizontalDirection()); + state = state.with(face, AnchorType.WALL).with(facing, direction.opposite().toHorizontalDirection()); } if (FastNMS.INSTANCE.method$BlockStateBase$canSurvive(state.customBlockState().literalObject(), context.getLevel().serverWorld(), LocationUtils.toBlockPos(context.getClickedPos()))) { return state; @@ -128,7 +128,7 @@ public class FaceAttachedHorizontalDirectionalBlockBehavior extends BukkitBlockB if (state == null) return null; FaceAttachedHorizontalDirectionalBlockBehavior behavior = state.behavior().getAs(FaceAttachedHorizontalDirectionalBlockBehavior.class).orElse(null); if (behavior == null) return null; - return switch (state.get(behavior.attachFaceProperty)) { + return switch (state.get(behavior.anchorTypeProperty)) { case CEILING -> Direction.DOWN; case FLOOR -> Direction.UP; default -> state.get(behavior.facingProperty).toDirection(); @@ -140,11 +140,11 @@ public class FaceAttachedHorizontalDirectionalBlockBehavior extends BukkitBlockB @SuppressWarnings("unchecked") @Override public BlockBehavior create(CustomBlock block, Map arguments) { - Property attachFace = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("face"), "warning.config.block.behavior.face_attached_horizontal_directional.missing_face"); + Property anchorType = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("face"), "warning.config.block.behavior.face_attached_horizontal_directional.missing_face"); Property facing = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.face_attached_horizontal_directional.missing_facing"); Tuple, Set, Set> tuple = DirectionalAttachedBlockBehavior.readTagsAndState(arguments); boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", true), "blacklist"); - return new FaceAttachedHorizontalDirectionalBlockBehavior(block, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), attachFace, facing); + return new FaceAttachedHorizontalDirectionalBlockBehavior(block, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), anchorType, facing); } } } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 71250f8c3..e2ea5b94a 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -325,6 +325,9 @@ warning.config.block.behavior.fence.missing_north: "Issue found in file warning.config.block.behavior.fence.missing_east: "Issue found in file - The block '' is missing the required 'east' property for 'fence_block' behavior." warning.config.block.behavior.fence.missing_south: "Issue found in file - The block '' is missing the required 'south' property for 'fence_block' behavior." warning.config.block.behavior.fence.missing_west: "Issue found in file - The block '' is missing the required 'west' property for 'fence_block' behavior." +warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "Issue found in file - The block '' is missing the required 'face' property for 'face_attached_horizontal_directional_block' behavior." +warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'face_attached_horizontal_directional_block' behavior." +warning.config.block.behavior.button.missing_powered: "Issue found in file - The block '' is missing the required 'powered' property for 'button_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.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." 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: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 1c2c4ca57..add5680d3 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -319,6 +319,9 @@ warning.config.block.behavior.fence.missing_north: "在文件 warning.config.block.behavior.fence.missing_east: "在文件 发现问题 - 方块 '' 的 'fence_block' 行为缺少必需的 'east' 属性" warning.config.block.behavior.fence.missing_south: "在文件 发现问题 - 方块 '' 的 'fence_block' 行为缺少必需的 'south' 属性" warning.config.block.behavior.fence.missing_west: "在文件 发现问题 - 方块 '' 的 'fence_block' 行为缺少必需的 'west' 属性" +warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "在文件 发现问题 - 方块 '' 的 'face_attached_horizontal_directional_block' 行为缺少必需的 'face' 属性" +warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "在文件 发现问题 - 方块 '' 的 'face_attached_horizontal_directional_block' 行为缺少必需的 'facing' 属性" +warning.config.block.behavior.button.missing_powered: "在文件 发现问题 - 方块 '' 的 'button_block' 行为缺少必需的 'powered' 属性" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" 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 e559a080a..42753ec45 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 @@ -22,7 +22,7 @@ public final class Properties { public static final Key STAIRS_SHAPE = Key.of("craftengine:stairs_shape"); public static final Key SLAB_TYPE = Key.of("craftengine:slab_type"); public static final Key SOFA_SHAPE = Key.of("craftengine:sofa_shape"); - public static final Key ATTACH_FACE = Key.of("craftengine:attach_face"); + public static final Key ANCHOR_TYPE = Key.of("craftengine:anchor_type"); static { register(BOOLEAN, BooleanProperty.FACTORY); @@ -39,7 +39,7 @@ public final class Properties { register(STAIRS_SHAPE, new EnumProperty.Factory<>(StairsShape.class)); register(SLAB_TYPE, new EnumProperty.Factory<>(SlabType.class)); register(SOFA_SHAPE, new EnumProperty.Factory<>(SofaShape.class)); - register(ATTACH_FACE, new EnumProperty.Factory<>(AttachFace.class)); + register(ANCHOR_TYPE, new EnumProperty.Factory<>(AnchorType.class)); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AttachFace.java b/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AnchorType.java similarity index 80% rename from core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AttachFace.java rename to core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AnchorType.java index de9d6267b..65bec0f74 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AttachFace.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AnchorType.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.block.state.properties; -public enum AttachFace { +public enum AnchorType { FLOOR, WALL, CEILING From a45feed63db6fae2cb11172478324b406a1c7f86 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Sun, 21 Sep 2025 04:22:44 +0800 Subject: [PATCH 037/125] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=85=BC=E5=AE=B91.2?= =?UTF-8?q?1.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/util/LegacyAuthLibUtils.java | 16 ++ .../block/behavior/FallingBlockBehavior.java | 7 +- .../bukkit/entity/data/EntityData.java | 7 + .../bukkit/entity/data/EntityDataValue.java | 3 +- .../item/factory/BukkitItemFactory.java | 2 +- .../plugin/command/BukkitCommandManager.java | 2 +- .../plugin/network/BukkitNetworkManager.java | 23 ++- .../handler/ProjectilePacketHandler.java | 15 +- .../reflection/minecraft/CoreReflections.java | 36 ++-- .../default/resourcepack/pack.mcmeta | 8 +- .../craftengine/core/block/BlockBehavior.java | 3 +- .../resolution/ResolutionMergePackMcMeta.java | 167 +++++++++++++----- .../core/util/FriendlyByteBuf.java | 65 +++++-- .../craftengine/core/util/MCUtils.java | 9 + .../core/util/MinecraftVersion.java | 1 + .../core/util/MinecraftVersions.java | 1 + .../craftengine/core/util/VersionHelper.java | 6 + .../craftengine/core/world/Vec3d.java | 1 + gradle.properties | 4 +- 19 files changed, 280 insertions(+), 96 deletions(-) create mode 100644 bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyAuthLibUtils.java diff --git a/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyAuthLibUtils.java b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyAuthLibUtils.java new file mode 100644 index 000000000..63a00b16e --- /dev/null +++ b/bukkit/legacy/src/main/java/net/momirealms/craftengine/bukkit/util/LegacyAuthLibUtils.java @@ -0,0 +1,16 @@ +package net.momirealms.craftengine.bukkit.util; + +import com.mojang.authlib.GameProfile; + +import java.util.UUID; + +public class LegacyAuthLibUtils { + + public static String getName(GameProfile profile) { + return profile.getName(); + } + + public static UUID getId(GameProfile profile) { + return profile.getId(); + } +} 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 e41956aec..48a99aa1f 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 @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -75,8 +76,7 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { Object level = args[0]; Object fallingBlockEntity = args[2]; Object entityData = CoreReflections.field$Entity$entityData.get(fallingBlockEntity); - boolean isSilent = (boolean) CoreReflections.method$SynchedEntityData$get.invoke(entityData, CoreReflections.instance$Entity$DATA_SILENT); - if (!isSilent) { + if (!BaseEntityData.Silent.get(entityData)) { Object blockState = CoreReflections.field$FallingBlockEntity$blockState.get(fallingBlockEntity); Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState); if (optionalCustomState.isEmpty()) return; @@ -93,12 +93,11 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { Object level = args[0]; Object pos = args[1]; Object entityData = CoreReflections.field$Entity$entityData.get(fallingBlock); - boolean isSilent = (boolean) CoreReflections.method$SynchedEntityData$get.invoke(entityData, CoreReflections.instance$Entity$DATA_SILENT); Object blockState = args[2]; int stateId = BlockStateUtils.blockStateToId(blockState); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (immutableBlockState == null || immutableBlockState.isEmpty()) return; - if (!isSilent) { + if (!BaseEntityData.Silent.get(entityData)) { net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); world.playBlockSound(Vec3d.atCenterOf(LocationUtils.fromBlockPos(pos)), immutableBlockState.settings().sounds().landSound()); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java index da99028c4..0574a93f9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.bukkit.entity.data; +import net.momirealms.craftengine.bukkit.nms.FastNMS; + import java.util.List; public interface EntityData { @@ -27,6 +29,11 @@ public interface EntityData { list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value)); } + @SuppressWarnings("unchecked") + default T get(Object entityData) { + return (T) FastNMS.INSTANCE.method$SynchedEntityData$get(entityData, entityDataAccessor()); + } + static EntityData of(Class clazz, Object serializer, T defaultValue) { return new SimpleEntityData<>(clazz, serializer, defaultValue); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java index fee5d034f..30d191d09 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java @@ -71,7 +71,8 @@ public class EntityDataValue { if (VersionHelper.isOrAbove1_21_5()) Serializers$OPTIONAL_LIVING_ENTITY_REFERENCE = initSerializersByName("OPTIONAL_LIVING_ENTITY_REFERENCE"); else Serializers$OPTIONAL_LIVING_ENTITY_REFERENCE = null; Serializers$OPTIONAL_GLOBAL_POS = initSerializersByName("OPTIONAL_GLOBAL_POS"); - Serializers$COMPOUND_TAG = initSerializersByName("COMPOUND_TAG"); + if (!VersionHelper.isOrAbove1_21_9()) Serializers$COMPOUND_TAG = initSerializersByName("COMPOUND_TAG"); + else Serializers$COMPOUND_TAG = null; Serializers$VILLAGER_DATA = initSerializersByName("VILLAGER_DATA"); Serializers$OPTIONAL_UNSIGNED_INT = initSerializersByName("OPTIONAL_UNSIGNED_INT"); Serializers$POSE = initSerializersByName("POSE"); 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 c8f760d99..f836d910b 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 @@ -49,7 +49,7 @@ public abstract class BukkitItemFactory> extend case "1.21.4" -> { return new ComponentItemFactory1_21_4(plugin); } - case "1.21.5", "1.21.6", "1.21.7", "1.21.8" -> { + case "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9" -> { return new ComponentItemFactory1_21_5(plugin); } default -> throw new IllegalStateException("Unsupported server version: " + plugin.serverVersion()); 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 9d80faf29..024b38db9 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 @@ -60,7 +60,7 @@ public class BukkitCommandManager extends AbstractCommandManager )); final LegacyPaperCommandManager manager = (LegacyPaperCommandManager) getCommandManager(); manager.settings().set(ManagerSetting.ALLOW_UNSAFE_REGISTRATION, true); - if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) { + if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER) && manager.hasCapability(CloudBukkitCapabilities.BRIGADIER)) { manager.registerBrigadier(); manager.brigadierManager().setNativeNumberSuggestions(true); } else if (manager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) { 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 4671b7ed5..7ced7ec1b 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 @@ -1815,8 +1815,13 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes @Override public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { GameProfile gameProfile = FastNMS.INSTANCE.field$ClientboundLoginFinishedPacket$gameProfile(packet); - user.setVerifiedName(gameProfile.getName()); - user.setVerifiedUUID(gameProfile.getId()); + if (VersionHelper.isOrAbove1_21_9()) { + user.setVerifiedName(gameProfile.name()); + user.setVerifiedUUID(gameProfile.id()); + } else { + user.setVerifiedName(LegacyAuthLibUtils.getName(gameProfile)); + user.setVerifiedUUID(LegacyAuthLibUtils.getId(gameProfile)); + } } } @@ -3533,6 +3538,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes double x = buf.readDouble(); double y = buf.readDouble(); double z = buf.readDouble(); + Vec3d movement = VersionHelper.isOrAbove1_21_9() ? buf.readLpVec3() : null; byte xRot = buf.readByte(); byte yRot = buf.readByte(); byte yHeadRot = buf.readByte(); @@ -3540,9 +3546,9 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes // Falling blocks int remapped = remapBlockState(data, user.clientModEnabled()); if (remapped != data) { - int xa = buf.readShort(); - int ya = buf.readShort(); - int za = buf.readShort(); + int xa = VersionHelper.isOrAbove1_21_9() ? -1 : buf.readShort(); + int ya = VersionHelper.isOrAbove1_21_9() ? -1 : buf.readShort(); + int za = VersionHelper.isOrAbove1_21_9() ? -1 : buf.readShort(); event.setChanged(true); buf.clear(); buf.writeVarInt(event.packetID()); @@ -3552,13 +3558,14 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes buf.writeDouble(x); buf.writeDouble(y); buf.writeDouble(z); + if (VersionHelper.isOrAbove1_21_9()) buf.writeLpVec3(movement); buf.writeByte(xRot); buf.writeByte(yRot); buf.writeByte(yHeadRot); buf.writeVarInt(remapped); - buf.writeShort(xa); - buf.writeShort(ya); - buf.writeShort(za); + if (!VersionHelper.isOrAbove1_21_9()) buf.writeShort(xa); + if (!VersionHelper.isOrAbove1_21_9()) buf.writeShort(ya); + if (!VersionHelper.isOrAbove1_21_9()) buf.writeShort(za); } }; this.handlers[MEntityTypes.ITEM_DISPLAY$registryId] = (user, event) -> { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java index 6e697af25..1524c7a39 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java @@ -18,6 +18,7 @@ import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.craftengine.core.world.Vec3d; import org.bukkit.inventory.ItemStack; import java.util.ArrayList; @@ -70,13 +71,14 @@ public class ProjectilePacketHandler implements EntityPacketHandler { double x = buf.readDouble(); double y = buf.readDouble(); double z = buf.readDouble(); + Vec3d movement = VersionHelper.isOrAbove1_21_9() ? buf.readLpVec3() : null; byte xRot = buf.readByte(); byte yRot = buf.readByte(); byte yHeadRot = buf.readByte(); int data = buf.readVarInt(); - int xa = buf.readShort(); - int ya = buf.readShort(); - int za = buf.readShort(); + int xa = VersionHelper.isOrAbove1_21_9() ? -1 : buf.readShort(); + int ya = VersionHelper.isOrAbove1_21_9() ? -1 : buf.readShort(); + int za = VersionHelper.isOrAbove1_21_9() ? -1 : buf.readShort(); event.setChanged(true); buf.clear(); buf.writeVarInt(event.packetID()); @@ -86,13 +88,14 @@ public class ProjectilePacketHandler implements EntityPacketHandler { buf.writeDouble(x); buf.writeDouble(y); buf.writeDouble(z); + if (VersionHelper.isOrAbove1_21_9()) buf.writeLpVec3(movement); buf.writeByte(MCUtils.packDegrees(MCUtils.clamp(-MCUtils.unpackDegrees(xRot), -90.0F, 90.0F))); buf.writeByte(MCUtils.packDegrees(-MCUtils.unpackDegrees(yRot))); buf.writeByte(yHeadRot); buf.writeVarInt(data); - buf.writeShort(xa); - buf.writeShort(ya); - buf.writeShort(za); + if (!VersionHelper.isOrAbove1_21_9()) buf.writeShort(xa); + if (!VersionHelper.isOrAbove1_21_9()) buf.writeShort(ya); + if (!VersionHelper.isOrAbove1_21_9()) buf.writeShort(za); } private Object convertCustomProjectilePositionSyncPacket(Object packet) { 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 571f99f4a..65a0549f6 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 @@ -667,9 +667,9 @@ public final class CoreReflections { ) ); - public static final Method method$SynchedEntityData$get = requireNonNull( - ReflectionUtils.getMethod(clazz$SynchedEntityData, Object.class, clazz$EntityDataAccessor) - ); + // public static final Method method$SynchedEntityData$get = requireNonNull( + // ReflectionUtils.getDeclaredMethod(clazz$SynchedEntityData, Object.class, new String[]{"get", VersionHelper.isOrAbove1_20_5() ? "a" : "b"}, clazz$EntityDataAccessor) + // ); public static final Class clazz$SynchedEntityData$DataValue = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( @@ -974,9 +974,9 @@ public final class CoreReflections { ReflectionUtils.getDeclaredField(clazz$PalettedContainer$Data, clazz$Palette, 0) ); - public static final Method method$Palette$write = requireNonNull( - ReflectionUtils.getMethod(clazz$Palette, void.class, clazz$FriendlyByteBuf) - ); + // public static final Method method$Palette$write = requireNonNull( + // ReflectionUtils.getMethod(clazz$Palette, void.class, clazz$FriendlyByteBuf) + // ); public static final Class clazz$ChunkAccess = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( @@ -1576,7 +1576,9 @@ public final class CoreReflections { ); public static final Method method$BlockBehaviour$getAnalogOutputSignal = requireNonNull( - ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, int.class, new String[]{"getAnalogOutputSignal", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos) + VersionHelper.isOrAbove1_21_9() + ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, int.class, new String[]{"getAnalogOutputSignal", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Direction) + : ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, int.class, new String[]{"getAnalogOutputSignal", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos) ); public static final Method method$Entity$level = requireNonNull( @@ -3609,23 +3611,23 @@ public final class CoreReflections { clazz$Registry, clazz$HolderLookup$RegistryLookup, new String[]{"asLookup", "p"} ); - public static final Field field$ServerEntity$broadcast = requireNonNull( - ReflectionUtils.getDeclaredField( - clazz$ServerEntity, Consumer.class, 0 - ) - ); + // public static final Field field$ServerEntity$broadcast = requireNonNull( + // ReflectionUtils.getDeclaredField( + // clazz$ServerEntity, Consumer.class, 0 + // ) + // ); - public static final MethodHandle methodHandle$ServerEntity$broadcastSetter; + // public static final MethodHandle methodHandle$ServerEntity$broadcastSetter; public static final MethodHandle methodHandle$ServerEntity$updateIntervalSetter; public static final MethodHandle methodHandle$ServerPlayer$connectionGetter; public static final MethodHandle methodHandle$ServerPlayer$getAttributeMethod; static { try { - methodHandle$ServerEntity$broadcastSetter = requireNonNull( - ReflectionUtils.unreflectSetter(field$ServerEntity$broadcast) - .asType(MethodType.methodType(void.class, Object.class, Consumer.class)) - ); + // methodHandle$ServerEntity$broadcastSetter = requireNonNull( + // ReflectionUtils.unreflectSetter(field$ServerEntity$broadcast) + // .asType(MethodType.methodType(void.class, Object.class, Consumer.class)) + // ); methodHandle$ServerEntity$updateIntervalSetter = requireNonNull( ReflectionUtils.unreflectSetter(field$ServerEntity$updateInterval) .asType(MethodType.methodType(void.class, Object.class, int.class)) diff --git a/common-files/src/main/resources/resources/default/resourcepack/pack.mcmeta b/common-files/src/main/resources/resources/default/resourcepack/pack.mcmeta index 0ae3705e1..4d5e8390e 100644 --- a/common-files/src/main/resources/resources/default/resourcepack/pack.mcmeta +++ b/common-files/src/main/resources/resources/default/resourcepack/pack.mcmeta @@ -1,10 +1,12 @@ { - "pack":{ + "pack": { "pack_format": 15, - "description":"CraftEngine", + "description": "CraftEngine", "supported_formats": { "min_inclusive": 15, "max_inclusive": 1000 - } + }, + "min_format": 15, + "max_format": 1000 } } \ No newline at end of file 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 e969cab8c..d81554d1a 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 @@ -100,7 +100,8 @@ public abstract class BlockBehavior { return false; } - // BlockState state, Level level, BlockPos pos + // 1.20.1~1.21.8 BlockState state, Level level, BlockPos pos + // 1.21.9+ BlockState state, Level level, BlockPos pos public int getAnalogOutputSignal(Object thisBlock, Object[] args) throws Exception { return 0; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java index 186a1c3eb..be609eeb1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java @@ -19,63 +19,148 @@ public class ResolutionMergePackMcMeta implements Resolution { this.description = description; } - private static class MinMax { - int min; - int max; - - MinMax(int min, int max) { - this.min = min; - this.max = max; - } + record MinMax(int min, int max) { } + @SuppressWarnings("DuplicatedCode") public static void mergeMcMeta(Path file1, Path file2, JsonElement customDescription) throws IOException { - JsonElement elem1 = GsonHelper.readJsonFile(file1); - JsonElement elem2 = GsonHelper.readJsonFile(file2); + JsonObject mcmeta1 = GsonHelper.readJsonFile(file1).getAsJsonObject(); + JsonObject mcmeta2 = GsonHelper.readJsonFile(file2).getAsJsonObject(); - JsonObject merged = mergeValues(elem1.getAsJsonObject(), elem2.getAsJsonObject()) - .getAsJsonObject(); + JsonObject merged = mergeValues(mcmeta1, mcmeta2).getAsJsonObject(); - if (merged.has("pack")) { - JsonObject pack = merged.getAsJsonObject("pack"); + if (mcmeta1.has("pack") && mcmeta2.has("pack")) { + JsonObject mergedPack = merged.getAsJsonObject("pack"); + JsonObject mcmeta1Pack = mcmeta1.getAsJsonObject("pack"); + JsonObject mcmeta2Pack = mcmeta2.getAsJsonObject("pack"); - int pf1 = elem1.getAsJsonObject().getAsJsonObject("pack") - .getAsJsonPrimitive("pack_format").getAsInt(); - int pf2 = elem2.getAsJsonObject().getAsJsonObject("pack") - .getAsJsonPrimitive("pack_format").getAsInt(); - pack.addProperty("pack_format", Math.max(pf1, pf2)); + int minPackFormat = Integer.MAX_VALUE; + int maxPackFormat = Integer.MIN_VALUE; + JsonArray mergedMinFormat = null; + JsonArray mergedMaxFormat = null; - JsonElement sf1 = elem1.getAsJsonObject().getAsJsonObject("pack") - .get("supported_formats"); - JsonElement sf2 = elem2.getAsJsonObject().getAsJsonObject("pack") - .get("supported_formats"); + if (mcmeta1Pack.has("pack_format") && mcmeta2Pack.has("pack_format")) { + int packFormat1 = mcmeta1Pack.getAsJsonPrimitive("pack_format").getAsInt(); + int packFormat2 = mcmeta2Pack.getAsJsonPrimitive("pack_format").getAsInt(); + int mergedPackFormat = maxPackFormat = Math.max(packFormat1, packFormat2); + minPackFormat = Math.min(packFormat1, packFormat2); + mergedPack.addProperty("pack_format", mergedPackFormat); + } else if (mcmeta1Pack.has("pack_format")) { + minPackFormat = maxPackFormat = mcmeta1Pack.getAsJsonPrimitive("pack_format").getAsInt(); + } else if (mcmeta2Pack.has("pack_format")) { + minPackFormat = maxPackFormat = mcmeta2Pack.getAsJsonPrimitive("pack_format").getAsInt(); + } - if (sf1 != null || sf2 != null) { - MinMax mergedMinMax = getMergedMinMax(sf1, sf2, pf1, pf2); + if (mcmeta1Pack.has("min_format") || mcmeta2Pack.has("min_format")) { + int[] minFormat1 = new int[]{Integer.MAX_VALUE, 0}; + int[] minFormat2 = new int[]{Integer.MAX_VALUE, 0}; - JsonElement mergedSf = createSupportedFormatsElement( - sf1 != null ? sf1 : sf2, + if (mcmeta1Pack.has("min_format")) { + JsonElement minFormat = mcmeta1Pack.get("min_format"); + if (minFormat.isJsonPrimitive()) { + minFormat1[0] = minFormat.getAsInt(); + } + if (minFormat.isJsonArray()) { + JsonArray minFormatArray = minFormat.getAsJsonArray(); + minFormat1[0] = minFormatArray.get(0).getAsInt(); + if (minFormatArray.size() > 1) { + minFormat1[1] = minFormatArray.get(1).getAsInt(); + } + } + } + + if (mcmeta2Pack.has("min_format")) { + JsonElement minFormat = mcmeta2Pack.get("min_format"); + if (minFormat.isJsonPrimitive()) { + minFormat2[0] = minFormat.getAsInt(); + } + if (mcmeta2Pack.isJsonArray()) { + JsonArray minFormatArray = minFormat.getAsJsonArray(); + minFormat2[0] = minFormatArray.get(0).getAsInt(); + if (minFormatArray.size() > 1) { + minFormat2[1] = minFormatArray.get(1).getAsInt(); + } + } + } + minPackFormat = Math.min(minPackFormat, Math.min(minFormat1[0], minFormat2[0])); + mergedMinFormat = new JsonArray(2); + mergedMinFormat.add(minPackFormat); + mergedMinFormat.add(Math.min(minFormat1[1], minFormat2[1])); + mergedPack.add("min_format", mergedMinFormat); + } + + if (mcmeta1Pack.has("max_format") || mcmeta2Pack.has("max_format")) { + int[] maxFormat1 = new int[]{Integer.MIN_VALUE, 0}; + int[] maxFormat2 = new int[]{Integer.MIN_VALUE, 0}; + + if (mcmeta1Pack.has("max_format")) { + JsonElement maxFormat = mcmeta1Pack.get("max_format"); + if (maxFormat.isJsonPrimitive()) { + maxFormat1[0] = maxFormat.getAsInt(); + } + if (maxFormat.isJsonArray()) { + JsonArray maxFormatArray = maxFormat.getAsJsonArray(); + maxFormat1[0] = maxFormatArray.get(0).getAsInt(); + if (maxFormatArray.size() > 1) { + maxFormat1[1] = maxFormatArray.get(1).getAsInt(); + } + } + } + + if (mcmeta2Pack.has("max_format")) { + JsonElement maxFormat = mcmeta2Pack.get("max_format"); + if (maxFormat.isJsonPrimitive()) { + maxFormat2[0] = maxFormat.getAsInt(); + } + if (maxFormat.isJsonArray()) { + JsonArray maxFormatArray = maxFormat.getAsJsonArray(); + maxFormat2[0] = maxFormatArray.get(0).getAsInt(); + if (maxFormatArray.size() > 1) { + maxFormat2[1] = maxFormatArray.get(1).getAsInt(); + } + } + } + + maxPackFormat = Math.max(maxPackFormat, Math.max(maxFormat1[0], maxFormat2[0])); + mergedMaxFormat = new JsonArray(2); + mergedMaxFormat.add(maxPackFormat); + mergedMaxFormat.add(Math.max(maxFormat1[1], maxFormat2[1])); + mergedPack.add("max_format", mergedMaxFormat); + } + + JsonElement supportedFormats1 = mcmeta1Pack.get("supported_formats"); + JsonElement supportedFormats2 = mcmeta2Pack.get("supported_formats"); + + if (supportedFormats1 != null || supportedFormats2 != null) { + MinMax mergedMinMax = getMergedMinMax(supportedFormats1, supportedFormats2, minPackFormat, maxPackFormat); + JsonElement mergedSupportedFormats = createSupportedFormatsElement( + supportedFormats1 != null ? supportedFormats1 : supportedFormats2, mergedMinMax.min, mergedMinMax.max ); - - pack.add("supported_formats", mergedSf); + if (mergedMinFormat != null && !mergedMinFormat.isEmpty()) { + mergedMinFormat.set(0, new JsonPrimitive(Math.min(mergedMinMax.min, mergedMinFormat.get(0).getAsInt()))); + } + if (mergedMaxFormat != null && !mergedMaxFormat.isEmpty()) { + mergedMaxFormat.set(0, new JsonPrimitive(Math.max(mergedMinMax.max, mergedMaxFormat.get(0).getAsInt()))); + } + mergedPack.add("supported_formats", mergedSupportedFormats); } if (customDescription != null) { - pack.add("description", customDescription); + mergedPack.add("description", customDescription); } else { - JsonPrimitive desc1 = elem1.getAsJsonObject().getAsJsonObject("pack") + JsonPrimitive description1 = mcmeta1.getAsJsonObject().getAsJsonObject("pack") .getAsJsonPrimitive("description"); - JsonPrimitive desc2 = elem2.getAsJsonObject().getAsJsonObject("pack") + JsonPrimitive description2 = mcmeta2.getAsJsonObject().getAsJsonObject("pack") .getAsJsonPrimitive("description"); - String mergedDesc = (desc1 != null ? desc1.getAsString() : "") - + (desc1 != null && desc2 != null ? "\n" : "") - + (desc2 != null ? desc2.getAsString() : ""); + String mergedDesc = (description1 != null ? description1.getAsString() : "") + + (description1 != null && description2 != null ? "\n" : "") + + (description2 != null ? description2.getAsString() : ""); if (!mergedDesc.isEmpty()) { - pack.addProperty("description", mergedDesc); + mergedPack.addProperty("description", mergedDesc); } } } @@ -83,16 +168,14 @@ public class ResolutionMergePackMcMeta implements Resolution { GsonHelper.writeJsonFile(merged, file1); } - private static MinMax getMergedMinMax(JsonElement sf1, JsonElement sf2, int pf1, int pf2) { + private static MinMax getMergedMinMax(JsonElement sf1, JsonElement sf2, int minPackFormat, int maxPackFormat) { MinMax mm1 = parseSupportedFormats(sf1); MinMax mm2 = parseSupportedFormats(sf2); int finalMin = Math.min(mm1.min, mm2.min); int finalMax = Math.max(mm1.max, mm2.max); - int pfMin = Math.min(pf1, pf2); - int pfMax = Math.max(pf1, pf2); - finalMin = Math.min(pfMin, finalMin); - finalMax = Math.max(pfMax, finalMax); + finalMin = Math.min(minPackFormat, finalMin); + finalMax = Math.max(maxPackFormat, finalMax); return new MinMax(finalMin, finalMax); } @@ -110,7 +193,7 @@ public class ResolutionMergePackMcMeta implements Resolution { if (supported.isJsonArray()) { JsonArray arr = supported.getAsJsonArray(); int min = arr.get(0).getAsInt(); - int max = arr.get(arr.size()-1).getAsInt(); + int max = arr.get(arr.size() - 1).getAsInt(); return new MinMax(min, max); } 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 68e30c8a2..62c582ee7 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 @@ -14,6 +14,7 @@ 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.craftengine.core.world.Vec3d; import net.momirealms.sparrow.nbt.NBT; import net.momirealms.sparrow.nbt.Tag; import org.jetbrains.annotations.NotNull; @@ -76,7 +77,7 @@ public class FriendlyByteBuf extends ByteBuf { public > C readCollection(IntFunction collectionFactory, Reader reader) { int i = this.readVarInt(); C collection = collectionFactory.apply(i); - for(int j = 0; j < i; ++j) { + for (int j = 0; j < i; ++j) { collection.add(reader.apply(this)); } return collection; @@ -93,7 +94,7 @@ public class FriendlyByteBuf extends ByteBuf { 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) { + for (int j = 0; j < i; ++j) { array[j] = reader.apply(this); } return array; @@ -101,7 +102,7 @@ public class FriendlyByteBuf extends ByteBuf { public void writeArray(T[] array, Writer writer) { this.writeVarInt(array.length); - for(T t : array) { + for (T t : array) { writer.accept(this, t); } } @@ -351,7 +352,7 @@ public class FriendlyByteBuf extends ByteBuf { } public long[] readFixedSizeLongArray(long[] output) { - for(int i = 0; i < output.length; ++i) { + for (int i = 0; i < output.length; ++i) { output[i] = this.readLong(); } return output; @@ -473,12 +474,12 @@ public class FriendlyByteBuf extends ByteBuf { public void writeHolderSet(Either, Key> holderSet) { holderSet.ifLeft( - ints -> { - writeVarInt(ints.size() + 1); - for (Integer anInt : ints) { - writeVarInt(anInt); + ints -> { + writeVarInt(ints.size() + 1); + for (Integer anInt : ints) { + writeVarInt(anInt); + } } - } ).ifRight(key -> { writeVarInt(0); writeKey(key); @@ -599,13 +600,57 @@ public class FriendlyByteBuf extends ByteBuf { @SuppressWarnings("unchecked") public > T readEnumConstant(Class enumClass) { - return (T)((Enum[])enumClass.getEnumConstants())[this.readVarInt()]; + return (T) ((Enum[]) enumClass.getEnumConstants())[this.readVarInt()]; } public FriendlyByteBuf writeEnumConstant(Enum instance) { return this.writeVarInt(instance.ordinal()); } + public Vec3d readLpVec3() { + int unsignedByte = this.readUnsignedByte(); + if (unsignedByte == 0) { + return Vec3d.ZERO; + } else { + int unsignedByte1 = this.readUnsignedByte(); + long unsignedInt = this.readUnsignedInt(); + long l = unsignedInt << 16 | (long) (unsignedByte1 << 8) | (long) unsignedByte; + long l1 = unsignedByte & 3; + if ((unsignedByte & 4) == 4) { + l1 |= ((long) this.readVarInt() & 4294967295L) << 2; + } + return new Vec3d( + (Math.min((double) ((l >> 3) & 32767L), (double) 32766.0F) * (double) 2.0F / (double) 32766.0F - (double) 1.0F) * (double) l1, + (Math.min((double) ((l >> 18) & 32767L), (double) 32766.0F) * (double) 2.0F / (double) 32766.0F - (double) 1.0F) * (double) l1, + (Math.min((double) ((l >> 33) & 32767L), (double) 32766.0F) * (double) 2.0F / (double) 32766.0F - (double) 1.0F) * (double) l1 + ); + } + } + + public void writeLpVec3(Vec3d vec3) { + double d = Double.isNaN(vec3.x) ? (double) 0.0F : Math.clamp(vec3.x, -1.7179869183E10, 1.7179869183E10); + double d1 = Double.isNaN(vec3.y) ? (double) 0.0F : Math.clamp(vec3.y, -1.7179869183E10, 1.7179869183E10); + double d2 = Double.isNaN(vec3.z) ? (double) 0.0F : Math.clamp(vec3.z, -1.7179869183E10, 1.7179869183E10); + double max = MCUtils.absMax(d, MCUtils.absMax(d1, d2)); + if (max < 3.051944088384301E-5) { + this.writeByte(0); + } else { + long l = MCUtils.ceilLong(max); + boolean flag = (l & 3L) != l; + long l1 = flag ? l & 3L | 4L : l; + long l2 = (Math.round(((d / (double) l) * (double) 0.5F + (double) 0.5F) * (double) 32766.0F)) << 3; + long l3 = (Math.round(((d1 / (double) l) * (double) 0.5F + (double) 0.5F) * (double) 32766.0F)) << 18; + long l4 = (Math.round(((d2 / (double) l) * (double) 0.5F + (double) 0.5F) * (double) 32766.0F)) << 33; + long l5 = l1 | l2 | l3 | l4; + this.writeByte((byte) ((int) l5)); + this.writeByte((byte) ((int) (l5 >> 8))); + this.writeInt((int) (l5 >> 16)); + if (flag) { + this.writeVarInt((int) (l >> 2)); + } + } + } + @FunctionalInterface public interface Writer extends BiConsumer { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java index 38cf3acdd..c78fc05d1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java @@ -282,4 +282,13 @@ public class MCUtils { public static double clamp(double value, double min, double max) { return value < min ? min : Math.min(value, max); } + + public static double absMax(double x, double y) { + return Math.max(Math.abs(x), Math.abs(y)); + } + + public static long ceilLong(double value) { + long l = (long)value; + return value > (double)l ? l + 1L : l; + } } 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 2e20c0a66..80fc10b38 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 @@ -22,6 +22,7 @@ public final class MinecraftVersion implements Comparable { PACK_FORMATS.put(1_21_06, 63); PACK_FORMATS.put(1_21_07, 64); PACK_FORMATS.put(1_21_08, 64); + PACK_FORMATS.put(1_21_09, 69); 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 2f28c73ad..b9c6980cc 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 @@ -19,5 +19,6 @@ public final class MinecraftVersions { 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 V1_21_8 = new MinecraftVersion("1.21.8"); + public static final MinecraftVersion V1_21_9 = new MinecraftVersion("1.21.9"); public static final MinecraftVersion FUTURE = new MinecraftVersion("1.99.99"); } 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 6b36f6bc3..2112ecd15 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 @@ -33,6 +33,7 @@ public class VersionHelper { private static final boolean v1_21_6; private static final boolean v1_21_7; private static final boolean v1_21_8; + private static final boolean v1_21_9; static { try (InputStream inputStream = Class.forName("net.minecraft.obfuscate.DontObfuscate").getResourceAsStream("/version.json")) { @@ -68,6 +69,7 @@ public class VersionHelper { v1_21_6 = version >= 12106; v1_21_7 = version >= 12107; v1_21_8 = version >= 12108; + v1_21_9 = version >= 12109; majorVersion = major; minorVersion = minor; @@ -239,4 +241,8 @@ public class VersionHelper { public static boolean isOrAbove1_21_8() { return v1_21_8; } + + public static boolean isOrAbove1_21_9() { + return v1_21_9; + } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java b/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java index aeb8b3df5..83ac823ba 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.util.MCUtils; public class Vec3d implements Position { + public static final Vec3d ZERO = new Vec3d(0, 0, 0); public final double x; public final double y; public final double z; diff --git a/gradle.properties b/gradle.properties index 1b25eea7b..6d228cad0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,13 +50,13 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.92 +nms_helper_version=1.0.93 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1 amazon_awssdk_eventstream_version=1.0.1 jimfs_version=1.3.0 -authlib_version=6.0.58 +authlib_version=7.0.60 concurrent_util_version=0.0.3 # Proxy settings From 6c0f816e03306627ffa1888dc804081dc5c3de85 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Mon, 22 Sep 2025 12:26:59 +0800 Subject: [PATCH 038/125] =?UTF-8?q?=E8=A1=A5=E6=BC=8F=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E6=9E=84=E5=BB=BA=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/legacy/build.gradle.kts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bukkit/legacy/build.gradle.kts b/bukkit/legacy/build.gradle.kts index 2de912779..5703f4c6f 100644 --- a/bukkit/legacy/build.gradle.kts +++ b/bukkit/legacy/build.gradle.kts @@ -10,6 +10,8 @@ repositories { dependencies { // Platform compileOnly("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT") + // authlib + compileOnly("com.mojang:authlib:6.0.58") } java { From de475746bd12e2b14d73c3ce31de4d1548e63461 Mon Sep 17 00:00:00 2001 From: iqtester <1835ww@gmail.com> Date: Mon, 22 Sep 2025 00:53:08 -0400 Subject: [PATCH 039/125] feat(BushBlockBehavior): added stackable-amount --- .../block/behavior/BushBlockBehavior.java | 30 +++++++++++++++++-- .../block/behavior/HangingBlockBehavior.java | 2 +- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index f20eab56d..7cb60c452 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -26,11 +26,13 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { protected final Set customBlocksCansSurviveOn; protected final boolean blacklistMode; protected final boolean stackable; + protected final int stackableAmount; - public BushBlockBehavior(CustomBlock block, int delay, boolean blacklist, boolean stackable, List tagsCanSurviveOn, Set blockStatesCanSurviveOn, Set customBlocksCansSurviveOn) { + public BushBlockBehavior(CustomBlock block, int delay, boolean blacklist, boolean stackable, int stackableAmount, List tagsCanSurviveOn, Set blockStatesCanSurviveOn, Set customBlocksCansSurviveOn) { super(block, delay); this.blacklistMode = blacklist; this.stackable = stackable; + this.stackableAmount = stackableAmount; this.tagsCanSurviveOn = tagsCanSurviveOn; this.blockStatesCanSurviveOn = blockStatesCanSurviveOn; this.customBlocksCansSurviveOn = customBlocksCansSurviveOn; @@ -42,9 +44,10 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { Tuple, Set, Set> tuple = readTagsAndState(arguments, false); boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable"); + int stackableAmount = ResourceConfigUtils.getAsInt(arguments.getOrDefault("stackable-amount", 0), "stackable-amount"); int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist"); - return new BushBlockBehavior(block, delay, blacklistMode, stackable, tuple.left(), tuple.mid(), tuple.right()); + return new BushBlockBehavior(block, delay, blacklistMode, stackable, stackableAmount,tuple.left(), tuple.mid(), tuple.right()); } } @@ -96,7 +99,11 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { } else { ImmutableBlockState belowCustomState = optionalCustomState.get(); if (belowCustomState.owner().value() == super.customBlock) { - return this.stackable; + if (!stackable) return false; + if (this.stackableAmount > 0) { + return mayStackOn(world, belowPos); + } + return true; } if (this.customBlocksCansSurviveOn.contains(belowCustomState.owner().value().id().toString())) { return !this.blacklistMode; @@ -107,4 +114,21 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { } return this.blacklistMode; } + + protected boolean mayStackOn(Object world, Object belowPos) { + int count = 0; + Object cursorPos = belowPos; + + while (count <= this.stackableAmount) { + Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, cursorPos); + Optional belowCustomState = BlockStateUtils.getOptionalCustomBlockState(belowState); + if (belowCustomState.isPresent() && belowCustomState.get().owner().value() == super.customBlock) { + count++; + cursorPos = LocationUtils.below(cursorPos); + } else { + break; + } + } + return count <= this.stackableAmount; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java index 594962aca..06724bc9f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/HangingBlockBehavior.java @@ -16,7 +16,7 @@ public class HangingBlockBehavior extends BushBlockBehavior { public static final Factory FACTORY = new Factory(); public HangingBlockBehavior(CustomBlock block, int delay, boolean blacklist, boolean stackable, List tagsCanSurviveOn, Set blocksCansSurviveOn, Set customBlocksCansSurviveOn) { - super(block, delay, blacklist, stackable, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); + super(block, delay, blacklist, stackable, -1, tagsCanSurviveOn, blocksCansSurviveOn, customBlocksCansSurviveOn); } @Override From 4f96c9c25ac56eff4da3e5cf397e08e6c967c7ae Mon Sep 17 00:00:00 2001 From: iqtester <1835ww@gmail.com> Date: Mon, 22 Sep 2025 06:39:52 -0400 Subject: [PATCH 040/125] feat(BushBlockBehavior): max-height --- .../block/behavior/BushBlockBehavior.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index 7cb60c452..bace95fe2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -26,13 +26,13 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { protected final Set customBlocksCansSurviveOn; protected final boolean blacklistMode; protected final boolean stackable; - protected final int stackableAmount; + protected final int maxHeight; - public BushBlockBehavior(CustomBlock block, int delay, boolean blacklist, boolean stackable, int stackableAmount, List tagsCanSurviveOn, Set blockStatesCanSurviveOn, Set customBlocksCansSurviveOn) { + public BushBlockBehavior(CustomBlock block, int delay, boolean blacklist, boolean stackable, int maxHeight, List tagsCanSurviveOn, Set blockStatesCanSurviveOn, Set customBlocksCansSurviveOn) { super(block, delay); this.blacklistMode = blacklist; this.stackable = stackable; - this.stackableAmount = stackableAmount; + this.maxHeight = maxHeight; this.tagsCanSurviveOn = tagsCanSurviveOn; this.blockStatesCanSurviveOn = blockStatesCanSurviveOn; this.customBlocksCansSurviveOn = customBlocksCansSurviveOn; @@ -44,10 +44,10 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { Tuple, Set, Set> tuple = readTagsAndState(arguments, false); boolean stackable = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("stackable", false), "stackable"); - int stackableAmount = ResourceConfigUtils.getAsInt(arguments.getOrDefault("stackable-amount", 0), "stackable-amount"); + int maxHeight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("max-height", 0), "max-height"); int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist"); - return new BushBlockBehavior(block, delay, blacklistMode, stackable, stackableAmount,tuple.left(), tuple.mid(), tuple.right()); + return new BushBlockBehavior(block, delay, blacklistMode, stackable, maxHeight,tuple.left(), tuple.mid(), tuple.right()); } } @@ -99,8 +99,8 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { } else { ImmutableBlockState belowCustomState = optionalCustomState.get(); if (belowCustomState.owner().value() == super.customBlock) { - if (!stackable) return false; - if (this.stackableAmount > 0) { + if (!this.stackable || this.maxHeight == 1) return false; + if (this.maxHeight > 1) { return mayStackOn(world, belowPos); } return true; @@ -116,10 +116,10 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { } protected boolean mayStackOn(Object world, Object belowPos) { - int count = 0; - Object cursorPos = belowPos; + int count = 1; + Object cursorPos = LocationUtils.below(belowPos); - while (count <= this.stackableAmount) { + while (count < this.maxHeight) { Object belowState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(world, cursorPos); Optional belowCustomState = BlockStateUtils.getOptionalCustomBlockState(belowState); if (belowCustomState.isPresent() && belowCustomState.get().owner().value() == super.customBlock) { @@ -129,6 +129,6 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { break; } } - return count <= this.stackableAmount; + return count < this.maxHeight; } } From d787f0bdfa807e973ca05c5929ef651f45315022 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Tue, 23 Sep 2025 11:28:58 +0800 Subject: [PATCH 041/125] =?UTF-8?q?feat(block):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E7=93=9C=E8=97=A4=E7=9B=B8=E5=85=B3=E7=9A=84=E6=96=B9=E5=9D=97?= =?UTF-8?q?=E8=A1=8C=E4=B8=BA=E5=B9=B6=E4=B8=94=E4=BF=AE=E5=A4=8D=E5=88=A4?= =?UTF-8?q?=E6=96=AD=E6=96=B9=E5=9D=97=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../behavior/AttachedStemBlockBehavior.java | 110 +++++++++++++ .../block/behavior/BukkitBlockBehaviors.java | 4 + .../block/behavior/CropBlockBehavior.java | 2 +- .../block/behavior/StemBlockBehavior.java | 154 ++++++++++++++++++ .../UnsafeCompositeBlockBehavior.java | 12 +- .../plugin/injector/BlockGenerator.java | 18 ++ .../plugin/injector/BlockStateGenerator.java | 74 +++++---- .../reflection/minecraft/CoreReflections.java | 10 ++ .../plugin/reflection/minecraft/MBlocks.java | 67 +++----- .../plugin/reflection/minecraft/MTagKeys.java | 1 + .../default/configuration/templates.yml | 14 +- .../src/main/resources/translations/en.yml | 6 + .../src/main/resources/translations/zh_cn.yml | 6 + .../craftengine/core/block/BlockBehavior.java | 8 +- gradle.properties | 4 +- 15 files changed, 399 insertions(+), 91 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java new file mode 100644 index 000000000..1e30aafb9 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java @@ -0,0 +1,110 @@ +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.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.IntegerProperty; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.util.*; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Callable; + +public class AttachedStemBlockBehavior extends BushBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final Property facingProperty; + private final Key fruit; + private final Key stem; + + public AttachedStemBlockBehavior(CustomBlock customBlock, + int delay, + boolean blacklist, + List tagsCanSurviveOn, + Set blockStatesCanSurviveOn, + Set customBlocksCansSurviveOn, + Property facingProperty, + Key fruit, + Key stem) { + super(customBlock, delay, blacklist, false, tagsCanSurviveOn, blockStatesCanSurviveOn, customBlocksCansSurviveOn); + this.facingProperty = facingProperty; + this.fruit = fruit; + this.stem = stem; + } + + @Override + public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) { + return FastNMS.INSTANCE.field$FluidState$isEmpty(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(args[0])); + } + + @Override + public boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + return (VersionHelper.isOrAbove1_20_5() ? args[1] : args[3]).equals(CoreReflections.instance$PathComputationType$AIR) + && !FastNMS.INSTANCE.field$BlockBehavior$hasCollision(thisBlock) || (boolean) superMethod.call(); + } + + @Override + public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + HorizontalDirection direction = DirectionUtils.fromNMSDirection(args[updateShape$direction]).toHorizontalDirection(); + Object neighborState = args[updateShape$neighborState]; + Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(state); + if (optionalCustomState.isEmpty() || direction != optionalCustomState.get().get(this.facingProperty)) { + return super.updateShape(thisBlock, args, superMethod); + } + Optional optionalCustomNeighborState = BlockStateUtils.getOptionalCustomBlockState(neighborState); + if (optionalCustomNeighborState.isPresent()) { + ImmutableBlockState customNeighborState = optionalCustomNeighborState.get(); + if (!customNeighborState.owner().value().id().equals(this.fruit)) { + Object stemBlock = resetStemBlock(); + if (stemBlock != null) return stemBlock; + } + } else { + if (this.stem.namespace().equals("minecraft")) { + Key neighborBlockId = BlockStateUtils.getBlockOwnerIdFromState(neighborState); + if (!neighborBlockId.equals(this.fruit)) { + Object stemBlock = resetStemBlock(); + if (stemBlock != null) return stemBlock; + } + } else { + Object stemBlock = resetStemBlock(); + if (stemBlock != null) return stemBlock; + } + } + return super.updateShape(thisBlock, args, superMethod); + } + + private Object resetStemBlock() { + Optional optionalStemBlock = BukkitBlockManager.instance().blockById(this.stem); + if (optionalStemBlock.isPresent()) { + CustomBlock stemBlock = optionalStemBlock.get(); + IntegerProperty ageProperty = (IntegerProperty) stemBlock.getProperty("age"); + if (ageProperty == null) return stemBlock.defaultState().customBlockState().literalObject(); + return stemBlock.defaultState().with(ageProperty, ageProperty.max).customBlockState().literalObject(); + } + return null; + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Tuple, Set, Set> tuple = readTagsAndState(arguments, false); + int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); + boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist"); + @SuppressWarnings("unchecked") + Property facingProperty = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.attached_stem.missing_facing"); + Key fruit = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("fruit"), "warning.config.block.behavior.attached_stem.missing_fruit")); + Key stem = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("stem"), "warning.config.block.behavior.attached_stem.missing_stem")); + return new AttachedStemBlockBehavior(block, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), facingProperty, fruit, stem); + } + } +} 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 fc8ba1cc6..ce5a59520 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 @@ -39,6 +39,8 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key FENCE_BLOCK = Key.from("craftengine:fence_block"); public static final Key BUTTON_BLOCK = Key.from("craftengine:button_block"); public static final Key FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK = Key.from("craftengine:face_attached_horizontal_directional_block"); + public static final Key STEM_BLOCK = Key.from("craftengine:stem_block"); + public static final Key ATTACHED_STEM_BLOCK = Key.from("craftengine:attached_stem_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -76,5 +78,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(FENCE_BLOCK, FenceBlockBehavior.FACTORY); register(BUTTON_BLOCK, ButtonBlockBehavior.FACTORY); register(FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK, FaceAttachedHorizontalDirectionalBlockBehavior.FACTORY); + register(STEM_BLOCK, StemBlockBehavior.FACTORY); + register(ATTACHED_STEM_BLOCK, AttachedStemBlockBehavior.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 7e0746ead..2e6793e35 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 @@ -77,7 +77,7 @@ public class CropBlockBehavior extends BukkitBlockBehavior { return minGrowLight; } - private static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { + public static int getRawBrightness(Object level, Object pos) throws InvocationTargetException, IllegalAccessException { return (int) CoreReflections.method$BlockAndTintGetter$getRawBrightness.invoke(level, pos, 0); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java new file mode 100644 index 000000000..d7d1180c3 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java @@ -0,0 +1,154 @@ +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.MBuiltInRegistries; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.UpdateOption; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.IntegerProperty; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.util.*; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Callable; + +public class StemBlockBehavior extends BushBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final IntegerProperty ageProperty; + private final Key fruit; + private final Key attachedStem; + private final int minGrowLight; + private final Object tagMayPlaceFruit; + private final Object blockMayPlaceFruit; + + public StemBlockBehavior(CustomBlock customBlock, + int delay, + boolean blacklist, + List tagsCanSurviveOn, + Set blockStatesCanSurviveOn, + Set customBlocksCansSurviveOn, + IntegerProperty ageProperty, + Key fruit, + Key attachedStem, + int minGrowLight, + Object tagMayPlaceFruit, + Object blockMayPlaceFruit) { + super(customBlock, delay, blacklist, false, tagsCanSurviveOn, blockStatesCanSurviveOn, customBlocksCansSurviveOn); + this.ageProperty = ageProperty; + this.fruit = fruit; + this.attachedStem = attachedStem; + this.minGrowLight = minGrowLight; + this.tagMayPlaceFruit = tagMayPlaceFruit; + this.blockMayPlaceFruit = blockMayPlaceFruit; + } + + @Override + public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) { + return FastNMS.INSTANCE.field$FluidState$isEmpty(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(args[0])); + } + + @Override + public boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + return (VersionHelper.isOrAbove1_20_5() ? args[1] : args[3]).equals(CoreReflections.instance$PathComputationType$AIR) + && !FastNMS.INSTANCE.field$BlockBehavior$hasCollision(thisBlock) || (boolean) superMethod.call(); + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + Object level = args[1]; + Object pos = args[2]; + if (CropBlockBehavior.getRawBrightness(level, pos) < this.minGrowLight) return; + ImmutableBlockState customState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); + if (customState == null || customState.isEmpty()) return; + int age = customState.get(ageProperty); + if (age < ageProperty.max) { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, customState.with(ageProperty, age + 1).customBlockState().literalObject(), 2); + return; + } + Object randomDirection = CoreReflections.instance$Direction$values[RandomUtils.generateRandomInt(2, 6)]; + Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(pos, randomDirection); + if (!FastNMS.INSTANCE.method$BlockStateBase$isAir(FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, blockPos))) + return; + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, FastNMS.INSTANCE.method$BlockPos$relative(blockPos, CoreReflections.instance$Direction$DOWN)); + if (mayPlaceFruit(blockState)) { + Optional optionalFruit = BukkitBlockManager.instance().blockById(this.fruit); + Object fruitState = null; + if (optionalFruit.isPresent()) { + fruitState = optionalFruit.get().defaultState().customBlockState().literalObject(); + } else if (fruit.namespace().equals("minecraft")) { + fruitState = FastNMS.INSTANCE.method$Block$defaultState(FastNMS.INSTANCE.method$Registry$getValue( + MBuiltInRegistries.BLOCK, + FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", fruit.value()) + )); + } + Optional optionalAttachedStem = BukkitBlockManager.instance().blockById(this.attachedStem); + if (fruitState == null || optionalAttachedStem.isEmpty()) return; + CustomBlock attachedStem = optionalAttachedStem.get(); + @SuppressWarnings("unchecked") + Property facing = (Property) attachedStem.getProperty("facing"); + if (facing == null) return; + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, fruitState, UpdateOption.UPDATE_ALL.flags()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, attachedStem.defaultState().with(facing, DirectionUtils.fromNMSDirection(randomDirection).toHorizontalDirection()).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); + } + } + + @Override + public boolean isValidBoneMealTarget(Object thisBlock, Object[] args) { + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[2]).orElse(null); + if (state == null || state.isEmpty()) return false; + return state.get(ageProperty) != ageProperty.max; + } + + @Override + public boolean isBoneMealSuccess(Object thisBlock, Object[] args) { + return true; + } + + @Override + public void performBoneMeal(Object thisBlock, Object[] args) { + ImmutableBlockState state = BlockStateUtils.getOptionalCustomBlockState(args[3]).orElse(null); + if (state == null || state.isEmpty()) return; + int min = Math.min(7, state.get(ageProperty) + RandomUtils.generateRandomInt(Math.min(ageProperty.min + 2, ageProperty.max), Math.min(ageProperty.max - 2, ageProperty.max))); + Object blockState = state.with(ageProperty, min).customBlockState().literalObject(); + FastNMS.INSTANCE.method$LevelWriter$setBlock(args[0], args[2], blockState, 2); + if (min >= ageProperty.max) { + FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$randomTick(blockState, args[0], args[2]); + } + } + + private boolean mayPlaceFruit(Object blockState) { + boolean flag1 = tagMayPlaceFruit != null && FastNMS.INSTANCE.method$BlockStateBase$is(blockState, tagMayPlaceFruit); + boolean flag2 = blockMayPlaceFruit != null && FastNMS.INSTANCE.method$BlockStateBase$isBlock(blockState, blockMayPlaceFruit); + if (tagMayPlaceFruit == null && blockMayPlaceFruit == null) return true; + return flag1 || flag2; + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + Tuple, Set, Set> tuple = readTagsAndState(arguments, false); + int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); + boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist"); + IntegerProperty ageProperty = (IntegerProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.stem.missing_age"); + Key fruit = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("fruit"), "warning.config.block.behavior.stem.missing_fruit")); + Key attachedStem = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("attached-stem"), "warning.config.block.behavior.stem.missing_attached_stem")); + int minGrowLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("light-requirement", 9), "light-requirement"); + Object tagMayPlaceFruit = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("may-place-fruit", "minecraft:dirt").toString()))); + Object blockMayPlaceFruit = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("may-place-fruit", "minecraft:farmland").toString()))); + return new StemBlockBehavior(block, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), ageProperty, fruit, attachedStem, minGrowLight, tagMayPlaceFruit, blockMayPlaceFruit); + } + } +} 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 2ab839d6b..8e9e4c631 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 @@ -381,4 +381,14 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior } FallOnBlockBehavior.super.updateEntityMovementAfterFallOn(thisBlock, args, superMethod); } -} \ No newline at end of file + + @Override + public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + if (!behavior.propagatesSkylightDown(thisBlock, args, superMethod)) { + return false; + } + } + return (boolean) superMethod.call(); + } +} 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 ae5e8c670..d54835999 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 @@ -170,6 +170,9 @@ public final class BlockGenerator { // stepOn .method(ElementMatchers.is(CoreReflections.method$Block$stepOn)) .intercept(MethodDelegation.to(StepOnInterceptor.INSTANCE)) + // propagatesSkylightDown + .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$propagatesSkylightDown)) + .intercept(MethodDelegation.to(PropagatesSkylightDownInterceptor.INSTANCE)) ; // 1.21.5+ if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) { @@ -760,4 +763,19 @@ public final class BlockGenerator { } } } + + public static class PropagatesSkylightDownInterceptor { + public static final PropagatesSkylightDownInterceptor INSTANCE = new PropagatesSkylightDownInterceptor(); + + @RuntimeType + public boolean intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + return holder.value().propagatesSkylightDown(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run propagatesSkylightDown", e); + return false; + } + } + } } \ No newline at end of file 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 148fa9e3d..03d0d98b0 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 @@ -12,7 +12,6 @@ import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.bind.annotation.AllArguments; import net.bytebuddy.implementation.bind.annotation.RuntimeType; -import net.bytebuddy.implementation.bind.annotation.SuperCall; import net.bytebuddy.implementation.bind.annotation.This; import net.bytebuddy.matcher.ElementMatchers; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; @@ -23,15 +22,16 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlockState import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MLootContextParams; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; -import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.BlockSettings; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.DelegatingBlockState; +import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.util.ObjectHolder; +import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.World; @@ -42,8 +42,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.List; -import java.util.Optional; -import java.util.concurrent.Callable; public final class BlockStateGenerator { private static MethodHandle constructor$CraftEngineBlockState; @@ -87,11 +85,11 @@ public final class BlockStateGenerator { Class clazz$CraftEngineBlock = stateBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded(); constructor$CraftEngineBlockState = VersionHelper.isOrAbove1_20_5() ? MethodHandles.publicLookup().in(clazz$CraftEngineBlock) - .findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class)) - .asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class)) : + .findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class)) + .asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, Reference2ObjectArrayMap.class, MapCodec.class)) : MethodHandles.publicLookup().in(clazz$CraftEngineBlock) - .findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class)) - .asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class)); + .findConstructor(clazz$CraftEngineBlock, MethodType.methodType(void.class, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class)) + .asType(MethodType.methodType(CoreReflections.clazz$BlockState, CoreReflections.clazz$Block, ImmutableMap.class, MapCodec.class)); String generatedFactoryClassName = packageWithName.substring(0, packageWithName.lastIndexOf('.')) + ".CraftEngineStateFactory"; DynamicType.Builder factoryBuilder = byteBuddy @@ -210,10 +208,12 @@ public final class BlockStateGenerator { DelegatingBlockState customState = (DelegatingBlockState) thisObj; ImmutableBlockState thisState = customState.blockState(); if (thisState == null) return false; - if (!(args[0] instanceof DelegatingBlock delegatingBlock)) return false; - BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); - if (behavior == null) return false; - return behavior.block().equals(thisState.owner().value()); + if (FastNMS.INSTANCE.method$Block$defaultState(args[0]) instanceof DelegatingBlockState holder) { + ImmutableBlockState holderState = holder.blockState(); + if (holderState == null) return false; + return holderState.owner().equals(thisState.owner()); + } + return false; } } @@ -226,13 +226,15 @@ public final class BlockStateGenerator { DelegatingBlockState customState = (DelegatingBlockState) thisObj; ImmutableBlockState thisState = customState.blockState(); if (thisState == null) return false; - CustomBlock thisBlock = thisState.owner().value(); + Holder owner = thisState.owner(); for (Object holder : (Iterable) args[0]) { Object block = FastNMS.INSTANCE.method$Holder$value(holder); - if (!(block instanceof DelegatingBlock delegatingBlock)) continue; - BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); - if (behavior == null) continue; - if (behavior.block().equals(thisBlock)) return true; + if (block == null) continue; + if (!(FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState customHolder)) + continue; + ImmutableBlockState holderState = customHolder.blockState(); + if (holderState == null) continue; + return holderState.owner().equals(owner); } return false; } @@ -243,15 +245,17 @@ public final class BlockStateGenerator { @RuntimeType public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - Object block = FastNMS.INSTANCE.method$Holder$value(args[0]); - if (!(block instanceof DelegatingBlock delegatingBlock)) return false; - BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); - if (behavior == null) return false; DelegatingBlockState customState = (DelegatingBlockState) thisObj; ImmutableBlockState thisState = customState.blockState(); if (thisState == null) return false; - CustomBlock thisBlock = thisState.owner().value(); - return behavior.block().equals(thisBlock); + Object block = FastNMS.INSTANCE.method$Holder$value(args[0]); + if (block == null) return false; + if (FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState holder) { + ImmutableBlockState holderState = holder.blockState(); + if (holderState == null) return false; + return holderState.owner().equals(thisState.owner()); + } + return false; } } @@ -260,17 +264,19 @@ public final class BlockStateGenerator { @RuntimeType public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - Object block = FastNMS.INSTANCE.method$HolderGetter$getResourceKey(MBuiltInRegistries.BLOCK, args[0]) - .map(FastNMS.INSTANCE::method$Holder$value) - .orElse(null); - if (!(block instanceof DelegatingBlock delegatingBlock)) return false; - BlockBehavior behavior = delegatingBlock.behaviorDelegate().value(); - if (behavior == null) return false; DelegatingBlockState customState = (DelegatingBlockState) thisObj; ImmutableBlockState thisState = customState.blockState(); if (thisState == null) return false; - CustomBlock thisBlock = thisState.owner().value(); - return behavior.block().equals(thisBlock); + Object block = FastNMS.INSTANCE.method$HolderGetter$getResourceKey(MBuiltInRegistries.BLOCK, args[0]) + .map(FastNMS.INSTANCE::method$Holder$value) + .orElse(null); + if (block == null) return false; + if (FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState holder) { + ImmutableBlockState holderState = holder.blockState(); + if (holderState == null) return false; + return holderState.owner().equals(thisState.owner()); + } + return false; } } 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 65a0549f6..345f5ab28 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 @@ -4434,4 +4434,14 @@ public final class CoreReflections { ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$ResourceKey), VersionHelper.isOrAbove1_20_3() ); + + public static final Method method$BlockBehaviour$propagatesSkylightDown = requireNonNull( + VersionHelper.isOrAbove1_21_2() + ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "e_"}, clazz$BlockState) + : VersionHelper.isOrAbove1_20_5() + ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) + : VersionHelper.isOrAbove1_20_4() + ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) + : ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) + ); } 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 d9c489fba..c08c66559 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 @@ -6,54 +6,31 @@ import net.momirealms.craftengine.core.util.VersionHelper; public final class MBlocks { private MBlocks() {} - public static final Object AIR; - public static final Object AIR$defaultState; - public static final Object STONE; - public static final Object STONE$defaultState; - public static final Object FIRE; - public static final Object SOUL_FIRE; - public static final Object ICE; - public static final Object SHORT_GRASS; - public static final Object SHORT_GRASS$defaultState; - public static final Object SHULKER_BOX; - public static final Object COMPOSTER; - public static final Object SNOW; - public static final Object WATER; - public static final Object WATER$defaultState; - public static final Object TNT; - public static final Object TNT$defaultState; - public static final Object BARRIER; - public static final Object CARVED_PUMPKIN; - public static final Object JACK_O_LANTERN; - public static final Object MELON; - public static final Object PUMPKIN; + public static final Object AIR = getById("air");; + public static final Object AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR); + public static final Object STONE = getById("stone"); + public static final Object STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE); + public static final Object FIRE = getById("fire"); + public static final Object SOUL_FIRE = getById("soul_fire"); + public static final Object ICE = getById("ice"); + public static final Object SHORT_GRASS = getById(VersionHelper.isOrAbove1_20_3() ? "short_grass" : "grass"); + public static final Object SHORT_GRASS$defaultState = FastNMS.INSTANCE.method$Block$defaultState(SHORT_GRASS); + public static final Object SHULKER_BOX = getById("shulker_box"); + public static final Object COMPOSTER = getById("composter"); + public static final Object SNOW = getById("snow"); + public static final Object WATER = getById("water"); + public static final Object WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); + public static final Object TNT = getById("tnt"); + public static final Object TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT); + public static final Object BARRIER = getById("barrier"); + public static final Object CARVED_PUMPKIN = getById("carved_pumpkin"); + public static final Object JACK_O_LANTERN = getById("jack_o_lantern"); + public static final Object MELON = getById("melon"); + public static final Object PUMPKIN = getById("pumpkin"); + public static final Object FARMLAND = getById("farmland"); private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, rl); } - - static { - 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"); - SNOW = getById("snow"); - WATER = getById("water"); - WATER$defaultState = FastNMS.INSTANCE.method$Block$defaultState(WATER); - TNT = getById("tnt"); - TNT$defaultState = FastNMS.INSTANCE.method$Block$defaultState(TNT); - BARRIER = getById("barrier"); - CARVED_PUMPKIN = getById("carved_pumpkin"); - JACK_O_LANTERN = getById("jack_o_lantern"); - MELON = getById("melon"); - PUMPKIN = getById("pumpkin"); - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java index fe3440027..3f444599e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MTagKeys.java @@ -12,6 +12,7 @@ public final class MTagKeys { public static final Object Block$SHULKER_BOXES = create(MRegistries.BLOCK, "shulker_boxes"); public static final Object Block$FENCES = create(MRegistries.BLOCK, "fences"); public static final Object Block$WOODEN_FENCES = create(MRegistries.BLOCK, "wooden_fences"); + public static final Object Block$DIRT = create(MRegistries.BLOCK, "dirt"); private static Object create(Object registry, String location) { Object resourceLocation = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", location); 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 e2c881a6c..8e2458b32 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -48,13 +48,13 @@ templates#models#block: generation: parent: minecraft:block/cube_column textures: - particle: minecraft:block/custom/block_particle - down: minecraft:block/custom/block_down - up: minecraft:block/custom/block_up - north: minecraft:block/custom/block_north - east: minecraft:block/custom/block_east - south: minecraft:block/custom/block_south - west: minecraft:block/custom/block_west + particle: ${particle_texture} + down: ${down_texture} + up: ${up_texture} + north: ${north_texture} + east: ${east_texture} + south: ${south_texture} + west: ${west_texture} # 2D items templates#models#2d: diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index e2ea5b94a..c12ee18f5 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -328,6 +328,12 @@ warning.config.block.behavior.fence.missing_west: "Issue found in file < warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "Issue found in file - The block '' is missing the required 'face' property for 'face_attached_horizontal_directional_block' behavior." warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'face_attached_horizontal_directional_block' behavior." warning.config.block.behavior.button.missing_powered: "Issue found in file - The block '' is missing the required 'powered' property for 'button_block' behavior." +warning.config.block.behavior.stem.missing_age: "Issue found in file - The block '' is missing the required 'age' property for 'stem_block' behavior." +warning.config.block.behavior.stem.missing_fruit: "Issue found in file - The block '' is missing the required 'fruit' argument for 'stem_block' behavior." +warning.config.block.behavior.stem.missing_attached_stem: "Issue found in file - The block '' is missing the required 'attached_stem' argument for 'stem_block' behavior." +warning.config.block.behavior.attached_stem.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'attached_stem_block' behavior." +warning.config.block.behavior.attached_stem.missing_fruit: "Issue found in file - The block '' is missing the required 'fruit' argument for 'attached_stem_block' behavior." +warning.config.block.behavior.attached_stem.missing_stem: "Issue found in file - The block '' is missing the required 'stem' argument for 'attached_stem_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.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." 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: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index add5680d3..462138c04 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -322,6 +322,12 @@ warning.config.block.behavior.fence.missing_west: "在文件 发 warning.config.block.behavior.face_attached_horizontal_directional.missing_face: "在文件 发现问题 - 方块 '' 的 'face_attached_horizontal_directional_block' 行为缺少必需的 'face' 属性" warning.config.block.behavior.face_attached_horizontal_directional.missing_facing: "在文件 发现问题 - 方块 '' 的 'face_attached_horizontal_directional_block' 行为缺少必需的 'facing' 属性" warning.config.block.behavior.button.missing_powered: "在文件 发现问题 - 方块 '' 的 'button_block' 行为缺少必需的 'powered' 属性" +warning.config.block.behavior.stem.missing_age: "在文件 发现问题 - 方块 '' 的 'stem_block' 行为缺少必需的 'age' 属性" +warning.config.block.behavior.stem.missing_fruit: "在文件 发现问题 - 方块 '' 的 'stem_block' 行为缺少必需的 'fruit' 选项" +warning.config.block.behavior.stem.missing_attached_stem: "在文件 发现问题 - 方块 '' 的 'stem_block' 行为缺少必需的 'attached_stem' 选项" +warning.config.block.behavior.attached_stem.missing_facing: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'facing' 属性" +warning.config.block.behavior.attached_stem.missing_fruit: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项" +warning.config.block.behavior.attached_stem.missing_stem: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" 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 d81554d1a..d3b82a4cd 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 @@ -184,6 +184,12 @@ public abstract class BlockBehavior { superMethod.call(); } + // 1.20.1~1.21.1 BlockState state, BlockGetter level, BlockPos pos + // 1.21.2+ BlockState state + public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + return (boolean) superMethod.call(); + } + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; } @@ -217,4 +223,4 @@ public abstract class BlockBehavior { } public abstract CustomBlock block(); -} \ No newline at end of file +} diff --git a/gradle.properties b/gradle.properties index 6d228cad0..1aa561ed6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G # Rule: [major update].[feature update].[bug fix] project_version=0.0.63.4 config_version=46 -lang_version=30 +lang_version=31 project_group=net.momirealms latest_supported_version=1.21.8 @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.93 +nms_helper_version=1.0.94 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1 From ea100a992d13d4d84f9c04e00119623e7a78c40f Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Tue, 23 Sep 2025 13:05:50 +0800 Subject: [PATCH 042/125] =?UTF-8?q?feat(block):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E5=92=8C=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E9=9A=8F=E6=9C=BA=E6=95=B0=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/blocks/honeydew.yml | 294 ++++++++++++++++++ .../default/configuration/categories.yml | 4 +- .../resources/default/configuration/i18n.yml | 12 +- .../textures/block/custom/honeydew.png | Bin 0 -> 463 bytes .../textures/block/custom/honeydew_bottom.png | Bin 0 -> 420 bytes .../textures/block/custom/honeydew_top.png | Bin 0 -> 493 bytes .../textures/item/custom/honeydew_item.png | Bin 0 -> 377 bytes .../src/main/resources/translations/en.yml | 2 + .../src/main/resources/translations/zh_cn.yml | 2 + .../core/pack/AbstractPackManager.java | 5 + .../number/BinomialNumberProvider.java | 51 +++ .../context/number/NumberProviders.java | 2 + 12 files changed, 370 insertions(+), 2 deletions(-) create mode 100644 common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/BinomialNumberProvider.java diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml b/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml new file mode 100644 index 000000000..12d8f5598 --- /dev/null +++ b/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml @@ -0,0 +1,294 @@ +items: + default:honeydew_item: + material: apple + data: + item-name: + model: + template: default:model/simplified_generated + arguments: + path: minecraft:item/custom/honeydew_item + behavior: + type: block_item + block: default:honeydew_stem + default:honeydew: + material: nether_brick + data: + item-name: + model: + path: minecraft:item/custom/honeydew + generation: + parent: minecraft:block/custom/honeydew + behavior: + type: block_item + block: default:honeydew + +blocks: + default:honeydew: + loot: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: default:honeydew + conditions: + - type: enchantment + predicate: minecraft:silk_touch>=1 + - type: item + item: default:honeydew_item + functions: + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: ore_drops + - type: set_count + add: false + count: 3~7 + - type: explosion_decay + settings: + map-color: 19 + hardness: 1 + resistance: 1 + push-reaction: DESTROY + is-suffocating: true + is-redstone-conductor: true + item: default:honeydew + tags: + - minecraft:enderman_holdable + - minecraft:mineable/axe + - minecraft:sword_efficient + incorrect-tool-dig-speed: 1 + state: + id: 30 + state: note_block:30 + model: + template: default:model/cube + arguments: + model: minecraft:block/custom/honeydew + particle_texture: minecraft:block/custom/honeydew + down_texture: minecraft:block/custom/honeydew_bottom + up_texture: minecraft:block/custom/honeydew_top + north_texture: minecraft:block/custom/honeydew + east_texture: minecraft:block/custom/honeydew + south_texture: minecraft:block/custom/honeydew + west_texture: minecraft:block/custom/honeydew + default:honeydew_stem: + loot: + pools: + - rolls: 1 + entries: + - type: item + item: default:honeydew_item + functions: + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 0 + count: + type: binomial + extra: 3 + probability: 0.06666667 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 1 + count: + type: binomial + extra: 3 + probability: 0.13333334 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 2 + count: + type: binomial + extra: 3 + probability: 0.2 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 3 + count: + type: binomial + extra: 3 + probability: 0.26666668 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 4 + count: + type: binomial + extra: 3 + probability: 0.33333334 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 5 + count: + type: binomial + extra: 3 + probability: 0.4 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 6 + count: + type: binomial + extra: 3 + probability: 0.46666667 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 7 + count: + type: binomial + extra: 3 + probability: 0.53333336 + functions: + - type: explosion_decay + settings: + map-color: 7 + hardness: 0 + resistance: 0 + push-reaction: DESTROY + is-suffocating: false + is-redstone-conductor: false + item: default:honeydew_item + is-randomly-ticking: true + tags: + - minecraft:bee_growables + - minecraft:crops + - minecraft:maintains_farmland + behaviors: + type: stem_block + fruit: default:honeydew + attached-stem: default:attached_honeydew_stem + blacklist: false + bottom-blocks: + - minecraft:farmland + states: + properties: + age: + type: int + default: 0 + range: 0~7 + appearances: + age=0: + state: pumpkin_stem[age=0] + age=1: + state: pumpkin_stem[age=1] + age=2: + state: pumpkin_stem[age=2] + age=3: + state: pumpkin_stem[age=3] + age=4: + state: pumpkin_stem[age=4] + age=5: + state: pumpkin_stem[age=5] + age=6: + state: pumpkin_stem[age=6] + age=7: + state: pumpkin_stem[age=7] + variants: + age=0: + appearance: age=0 + id: 0 + age=1: + appearance: age=1 + id: 1 + age=2: + appearance: age=2 + id: 2 + age=3: + appearance: age=3 + id: 3 + age=4: + appearance: age=4 + id: 4 + age=5: + appearance: age=5 + id: 5 + age=6: + appearance: age=6 + id: 6 + age=7: + appearance: age=7 + id: 7 + default:attached_honeydew_stem: + loot: + pools: + - rolls: 1 + entries: + - type: item + item: default:honeydew_item + functions: + - type: set_count + add: false + count: + type: binomial + extra: 3 + probability: 0.53333336 + functions: + - type: explosion_decay + settings: + map-color: 7 + hardness: 0 + resistance: 0 + push-reaction: DESTROY + is-suffocating: false + is-redstone-conductor: false + item: default:honeydew_item + is-randomly-ticking: true + tags: + - minecraft:maintains_farmland + behaviors: + type: attached_stem_block + fruit: default:honeydew + stem: default:honeydew_stem + blacklist: false + bottom-blocks: + - minecraft:farmland + states: + properties: + facing: + type: horizontal_direction + default: north + appearances: + facing=east: + state: attached_pumpkin_stem[facing=east] + facing=south: + state: attached_pumpkin_stem[facing=south] + facing=west: + state: attached_pumpkin_stem[facing=west] + facing=north: + state: attached_pumpkin_stem[facing=north] + variants: + facing=east: + appearance: facing=east + id: 0 + facing=south: + appearance: facing=south + id: 1 + facing=west: + appearance: facing=west + id: 2 + facing=north: + appearance: facing=north + id: 3 diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 55610a412..6f02cfd78 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -78,4 +78,6 @@ categories: - default:bench - default:wooden_chair - default:flower_basket - - default:amethyst_torch \ No newline at end of file + - default:amethyst_torch + - default:honeydew_item + - default:honeydew \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index fa91ebbb0..fbd75318d 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -49,6 +49,8 @@ i18n: item.safe_block: Safe Block item.sofa: Sofa item.amethyst_torch: Amethyst Torch + item.honeydew_item: Honeydew Slice + item.honeydew: Honeydew category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -107,6 +109,8 @@ i18n: item.safe_block: 保险柜 item.sofa: 沙发 item.amethyst_torch: 紫水晶火把 + item.honeydew_item: 哈密瓜片 + item.honeydew: 哈密瓜 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 @@ -149,6 +153,9 @@ lang: block_name:default:sofa: Sofa block_name:default:amethyst_torch: Amethyst Torch block_name:default:amethyst_wall_torch: Amethyst Torch + block_name:default:honeydew: Honeydew + block_name:default:honeydew_stem: Honeydew Stem + block_name:default:default:attached_honeydew_stem: Honeydew Stem zh_cn: block_name:default:chinese_lantern: 灯笼 block_name:default:netherite_anvil: 下界合金砧 @@ -178,4 +185,7 @@ lang: block_name:default:sleeper_sofa: 沙发 block_name:default:sofa: 沙发 block_name:default:amethyst_torch: 紫水晶火把 - block_name:default:amethyst_wall_torch: 紫水晶火把 \ No newline at end of file + block_name:default:amethyst_wall_torch: 紫水晶火把 + block_name:default:honeydew: 哈密瓜 + block_name:default:honeydew_stem: 哈密瓜茎 + block_name:default:default:attached_honeydew_stem: 哈密瓜茎 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png new file mode 100644 index 0000000000000000000000000000000000000000..df74b134bb10be3dbd46afc1bf2d9c71129a8fc8 GIT binary patch literal 463 zcmV;=0WkiFP)Px$iAh93R49>6k-=(%KoEw1MJU0NV_kYE;=xN1qz@3tNuMRqLLfdx0);+EPd&s_ zArBA&O9*&KB!sZ`C|$%$?BTbIdm5dY@Be4Udi_kYI9RJH6&`?L03a3KFpx?+k#O<< znCr%)yeOs8CMA^y2&x?Nq|#CyvpDF+qyGvdq2B>1JfJdAo7BbRne5eOpBLp~@*D}* zs++thjmd62l1e+2OU6Dcj0o{iz568eso-#+4oE^Db+c9#6q3+iZT69H&Cmeyq6A=5 zi|S0I!lNr=Ln>|64MiL}F_^w+r-3pFeNwnCt8OCU+FXd)G%+;8NruLx(l&ths@W!$ zUTyYP-LN7rN~>;$*92f^abV0u!p-7fxjPQ-g;aQ{@Rqw{d)1L}`#Z3XU?QZ_3`}XS zAeFv*bla;wU0QlutE#=~w+D}I0et*a)7yPNgYoeG@-%evZU6Fr76+$G%eE{IY~y&o zJu`TF@aEg|^mb2?+1J6aW?u)J-R7Ck`S$$rQw>>6{Q*}Z5xyxv;}ZY?002ovPDHLk FV1g!V(KrAA literal 0 HcmV?d00001 diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..a21c39cec5bfbd841da2aecdb77dc0b23131c39a GIT binary patch literal 420 zcmV;V0bBlwP)Px$UP(kjR5*=YQa^8kKoozOE_LR{2rX^4x! zGhqfI=qwwhhrt>g_Z$6P*b=8_O+*zu(6Uj1XL1j7r@qAFBDX>7r_akJa@>_kU%x*e zwgu?!tWsa@&T4m7+r=y{>bGZk%YfFT>M)j(EfE^@Svbc?Q2F<3jBH6&hnWCJM45fF zgs2Zo2jjXNTLPx$r%6OXR49>MQcX+4KoFg@sUb85^pZVjiKPvcQYginQ1FzTyn3r=1rLJ#6&CtW zM8rdS?LiPk3ZV$4AE8v(2vxC-QU&AT*==x7vokyIy?Hy*>7`v_X@?mu4~Qrp5RuD+ zcyQ4fChFxZ9>ohD5C8S!lvp|uzoRG8)e=kFmKo_PssheohAc25U2U|x=hb4X=i8Rq z>iI;3z_!eY2pJiDk*;9wZBgnf^Q+Oy91$Pqm7bPbrPN z-rmM~PSa-eh347fqgJszJF;}GLf!= z`Mg>L)=Cn9@$0C$Jn(oZjF#R%T^`8sv50(F3>o!umMDmSi^GiNKMFfdBPXnu!~SF^3x}D(^vz*Le;(#j%8b4YZSCLkKF_~z`Rh?`JEv(f jw2Ji-D;Ph5(Bt7Rur?NdAIn!}00000NkvXXu0mjfg*Mxx literal 0 HcmV?d00001 diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png new file mode 100644 index 0000000000000000000000000000000000000000..5c46ede57f362cf847e055b5a49d59ae749c495a GIT binary patch literal 377 zcmV-<0fzpGP)Px$Gf6~2R5*>jlD$g9P#A`vRz)O%h}2GLJ?dhMAYGhX70D{N7O{g{K@hx#fL=kb zp!5oyow^j46cM2shhjjIK}1qH4&{U#Oeli*ZQuFM^S#KK!DTs zI-wWPGb^&+^$Rlv6nJq}2jK1bL!0Lcq#XeUogr%ng3t?Q3%HJuNBbtr^;Mp3MgTNg zwZuJoc~ABh^AeF5^o+|;7wm(sF9U;|Qt5R_De){oV zZyz;xEkV!xB6^59Uz{Yv>rXX~GhrIssue found in file warning.config.number.uniform.missing_max: "Issue found in file - The config '' is missing the required 'max' argument for 'uniform' number." warning.config.number.gaussian.missing_min: "Issue found in file - The config '' is missing the required 'min' argument for 'gaussian' number." warning.config.number.gaussian.missing_max: "Issue found in file - The config '' is missing the required 'max' argument for 'gaussian' number." +warning.config.number.binomial.missing_extra: "Issue found in file - The config '' is missing the required 'extra' argument for 'binomial' number." +warning.config.number.binomial.missing_probability: "Issue found in file - The config '' is missing the required 'probability' argument for 'binomial' number." warning.config.condition.all_of.missing_terms: "Issue found in file - The config '' is missing the required 'terms' argument for 'all_of' condition." warning.config.condition.all_of.invalid_terms_type: "Issue found in file - The config '' has a misconfigured 'all_of' condition, 'terms' should be a map list, current type: ''." warning.config.condition.any_of.missing_terms: "Issue found in file - The config '' is missing the required 'terms' argument for 'any_of' condition." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 462138c04..6f5171988 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -87,6 +87,8 @@ warning.config.number.uniform.missing_min: "在文件 发现问 warning.config.number.uniform.missing_max: "在文件 发现问题 - 配置项 '' 缺少 'uniform' 数字类型所需的 'max' 参数" warning.config.number.gaussian.missing_min: "在文件 发现问题 - 配置项 '' 缺少 'gaussian' 数字类型所需的 'min' 参数" warning.config.number.gaussian.missing_max: "在文件 发现问题 - 配置项 '' 缺少 'gaussian' 数字类型所需的 'max' 参数" +warning.config.number.binomial.missing_extra: "在文件 发现问题 - 配置项 '' 缺少 'binomial' 数字类型所需的 'extra' 参数" +warning.config.number.binomial.missing_probability: "在文件 发现问题 - 配置项 '' 缺少 'binomial' 数字类型所需的 'probability' 参数" warning.config.condition.all_of.missing_terms: "在文件 发现问题 - 配置项 '' 缺少 'all_of' 条件所需的 'terms' 参数" warning.config.condition.all_of.invalid_terms_type: "在文件 发现问题 - 配置项 '' 的 'all_of' 条件配置错误, 'terms' 应为映射列表, 当前类型: ''" warning.config.condition.any_of.missing_terms: "在文件 发现问题 - 配置项 '' 缺少 'any_of' 条件所需的 'terms' 参数" 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 62898220f..b3eafb708 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 @@ -431,6 +431,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/configuration/blocks/topaz_ore.yml"); plugin.saveResource("resources/default/configuration/blocks/netherite_anvil.yml"); plugin.saveResource("resources/default/configuration/blocks/amethyst_torch.yml"); + plugin.saveResource("resources/default/configuration/blocks/honeydew.yml"); // assets plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/font/image/emojis.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/chinese_lantern.png"); @@ -537,6 +538,10 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_background.png.mcmeta"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png.mcmeta"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png"); } private TreeMap> updateCachedConfigFiles() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/BinomialNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/BinomialNumberProvider.java new file mode 100644 index 000000000..3d2306df8 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/BinomialNumberProvider.java @@ -0,0 +1,51 @@ +package net.momirealms.craftengine.core.plugin.context.number; + +import net.momirealms.craftengine.core.plugin.context.Context; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; + +public record BinomialNumberProvider(NumberProvider trials, NumberProvider successProbability) implements NumberProvider { + public static final Factory FACTORY = new Factory(); + + @Override + public float getFloat(Context context) { + return getInt(context); + } + + @Override + public double getDouble(Context context) { + return getInt(context); + } + + @Override + public int getInt(Context context) { + int trialCount = this.trials.getInt(context); + float probability = this.successProbability.getFloat(context); + int successCount = 0; + + for (int i = 0; i < trialCount; i++) { + if (RandomUtils.generateRandomFloat(0, 1) < probability) { + successCount++; + } + } + return successCount; + } + + @Override + public Key type() { + return NumberProviders.BINOMIAL; + } + + public static class Factory implements NumberProviderFactory { + + @Override + public NumberProvider create(Map arguments) { + Object trials = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("extra"), "warning.config.number.binomial.missing_extra"); + Object successProbability = ResourceConfigUtils.requireNonNullOrThrow(arguments.get("probability"), "warning.config.number.binomial.missing_probability"); + return new BinomialNumberProvider(NumberProviders.fromObject(trials), NumberProviders.fromObject(successProbability)); + } + } +} 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 49ce77b1a..0b46ffb92 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 @@ -18,6 +18,7 @@ public class NumberProviders { public static final Key UNIFORM = Key.of("craftengine:uniform"); public static final Key EXPRESSION = Key.of("craftengine:expression"); public static final Key GAUSSIAN = Key.of("craftengine:gaussian"); + public static final Key BINOMIAL = Key.of("craftengine:binomial"); static { register(FIXED, FixedNumberProvider.FACTORY); @@ -25,6 +26,7 @@ public class NumberProviders { register(UNIFORM, UniformNumberProvider.FACTORY); register(GAUSSIAN, GaussianNumberProvider.FACTORY); register(EXPRESSION, ExpressionNumberProvider.FACTORY); + register(BINOMIAL, BinomialNumberProvider.FACTORY); } public static void register(Key key, NumberProviderFactory factory) { From 895b903e6b8c600272bf19a5204c0a2649c70fb1 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Tue, 23 Sep 2025 13:10:24 +0800 Subject: [PATCH 043/125] =?UTF-8?q?=E8=A1=A5=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/additional-real-blocks.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common-files/src/main/resources/additional-real-blocks.yml b/common-files/src/main/resources/additional-real-blocks.yml index 2c6f2c87d..98472f7de 100644 --- a/common-files/src/main/resources/additional-real-blocks.yml +++ b/common-files/src/main/resources/additional-real-blocks.yml @@ -84,4 +84,6 @@ minecraft:warped_fence_gate: 16 minecraft:barrier: 128 minecraft:white_bed: 1 minecraft:redstone_torch: 1 -minecraft:redstone_wall_torch: 4 \ No newline at end of file +minecraft:redstone_wall_torch: 4 +minecraft:pumpkin_stem: 8 +minecraft:attached_pumpkin_stem: 4 \ No newline at end of file From 5558a6d67323c450cb16eac17ea1af7dff4b729b Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Tue, 23 Sep 2025 13:28:44 +0800 Subject: [PATCH 044/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BD=8E=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/reflection/minecraft/CoreReflections.java | 4 ++-- .../bukkit/plugin/reflection/minecraft/MBlocks.java | 2 +- .../resources/default/configuration/blocks/honeydew.yml | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) 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 345f5ab28..64590cb41 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 @@ -4441,7 +4441,7 @@ public final class CoreReflections { : VersionHelper.isOrAbove1_20_5() ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) : VersionHelper.isOrAbove1_20_4() - ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) - : ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) + ? ReflectionUtils.getDeclaredMethod(clazz$Block, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) + : ReflectionUtils.getDeclaredMethod(clazz$Block, boolean.class, new String[]{"propagatesSkylightDown", "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) ); } 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 c08c66559..79389af1c 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 @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.util.VersionHelper; public final class MBlocks { private MBlocks() {} - public static final Object AIR = getById("air");; + public static final Object AIR = getById("air"); public static final Object AIR$defaultState = FastNMS.INSTANCE.method$Block$defaultState(AIR); public static final Object STONE = getById("stone"); public static final Object STONE$defaultState = FastNMS.INSTANCE.method$Block$defaultState(STONE); diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml b/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml index 12d8f5598..25400f3ec 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml @@ -1,6 +1,7 @@ items: default:honeydew_item: material: apple + custom-model-data: 1000 data: item-name: model: @@ -12,6 +13,7 @@ items: block: default:honeydew_stem default:honeydew: material: nether_brick + custom-model-data: 3023 data: item-name: model: From ec0c61324d3f5ea07d3d5d9e1d934ced2f78295d Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Tue, 23 Sep 2025 14:33:19 +0800 Subject: [PATCH 045/125] =?UTF-8?q?=E5=9B=9E=E9=80=80=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0=EF=BC=8C=E6=B7=BB=E5=8A=A0=E9=99=90?= =?UTF-8?q?=E5=88=B6=E6=95=B0=E9=87=8F=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/injector/BlockStateGenerator.java | 80 +------------------ .../reflection/minecraft/CoreReflections.java | 16 ---- .../default/configuration/blocks/honeydew.yml | 8 +- .../loot/function/LimitCountFunction.java | 65 +++++++++++++++ .../core/loot/function/LootFunctions.java | 2 + 5 files changed, 73 insertions(+), 98 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/loot/function/LimitCountFunction.java 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 03d0d98b0..2c2e4d036 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 @@ -19,19 +19,16 @@ 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.MBlockStateProperties; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MLootContextParams; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.block.BlockSettings; -import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.DelegatingBlockState; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.ReflectionUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.World; @@ -69,19 +66,7 @@ public final class BlockStateGenerator { .method(ElementMatchers.is(CoreReflections.method$StateHolder$setValue)) .intercept(MethodDelegation.to(SetPropertyValueInterceptor.INSTANCE)) .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isBlock)) - .intercept(MethodDelegation.to(IsBlockInterceptor.INSTANCE)) - .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isHolderSetBlock)) - .intercept(MethodDelegation.to(IsHolderSetBlockInterceptor.INSTANCE)); - if (CoreReflections.method$BlockStateBase$isHolderBlock != null) { - stateBuilder = stateBuilder - .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isHolderBlock)) - .intercept(MethodDelegation.to(IsHolderBlockInterceptor.INSTANCE)); - } - if (CoreReflections.method$BlockStateBase$isResourceKeyBlock != null) { - stateBuilder = stateBuilder - .method(ElementMatchers.is(CoreReflections.method$BlockStateBase$isResourceKeyBlock)) - .intercept(MethodDelegation.to(IsResourceKeyBlockInterceptor.INSTANCE)); - } + .intercept(MethodDelegation.to(IsBlockInterceptor.INSTANCE)); Class clazz$CraftEngineBlock = stateBuilder.make().load(BlockStateGenerator.class.getClassLoader()).getLoaded(); constructor$CraftEngineBlockState = VersionHelper.isOrAbove1_20_5() ? MethodHandles.publicLookup().in(clazz$CraftEngineBlock) @@ -217,69 +202,6 @@ public final class BlockStateGenerator { } } - public static class IsHolderSetBlockInterceptor { - public static final IsHolderSetBlockInterceptor INSTANCE = new IsHolderSetBlockInterceptor(); - - @SuppressWarnings("unchecked") - @RuntimeType - public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - DelegatingBlockState customState = (DelegatingBlockState) thisObj; - ImmutableBlockState thisState = customState.blockState(); - if (thisState == null) return false; - Holder owner = thisState.owner(); - for (Object holder : (Iterable) args[0]) { - Object block = FastNMS.INSTANCE.method$Holder$value(holder); - if (block == null) continue; - if (!(FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState customHolder)) - continue; - ImmutableBlockState holderState = customHolder.blockState(); - if (holderState == null) continue; - return holderState.owner().equals(owner); - } - return false; - } - } - - public static class IsHolderBlockInterceptor { - public static final IsHolderBlockInterceptor INSTANCE = new IsHolderBlockInterceptor(); - - @RuntimeType - public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - DelegatingBlockState customState = (DelegatingBlockState) thisObj; - ImmutableBlockState thisState = customState.blockState(); - if (thisState == null) return false; - Object block = FastNMS.INSTANCE.method$Holder$value(args[0]); - if (block == null) return false; - if (FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState holder) { - ImmutableBlockState holderState = holder.blockState(); - if (holderState == null) return false; - return holderState.owner().equals(thisState.owner()); - } - return false; - } - } - - public static class IsResourceKeyBlockInterceptor { - public static final IsResourceKeyBlockInterceptor INSTANCE = new IsResourceKeyBlockInterceptor(); - - @RuntimeType - public boolean intercept(@This Object thisObj, @AllArguments Object[] args) { - DelegatingBlockState customState = (DelegatingBlockState) thisObj; - ImmutableBlockState thisState = customState.blockState(); - if (thisState == null) return false; - Object block = FastNMS.INSTANCE.method$HolderGetter$getResourceKey(MBuiltInRegistries.BLOCK, args[0]) - .map(FastNMS.INSTANCE::method$Holder$value) - .orElse(null); - if (block == null) return false; - if (FastNMS.INSTANCE.method$Block$defaultState(block) instanceof DelegatingBlockState holder) { - ImmutableBlockState holderState = holder.blockState(); - if (holderState == null) return false; - return holderState.owner().equals(thisState.owner()); - } - return false; - } - } - public static class CreateStateInterceptor { public static final CreateStateInterceptor INSTANCE = new CreateStateInterceptor(); 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 64590cb41..f4b0439d1 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 @@ -4419,22 +4419,6 @@ public final class CoreReflections { ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Block) ); - public static final Method method$BlockStateBase$isHolderSetBlock = requireNonNull( - ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$HolderSet) - ); - - // 1.20.2+ - public static final Method method$BlockStateBase$isHolderBlock = MiscUtils.requireNonNullIf( - ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Holder), - VersionHelper.isOrAbove1_20_2() - ); - - // 1.20.3+ - public static final Method method$BlockStateBase$isResourceKeyBlock = MiscUtils.requireNonNullIf( - ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$ResourceKey), - VersionHelper.isOrAbove1_20_3() - ); - public static final Method method$BlockBehaviour$propagatesSkylightDown = requireNonNull( VersionHelper.isOrAbove1_21_2() ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "e_"}, clazz$BlockState) diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml b/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml index 25400f3ec..0291afcbe 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml @@ -40,13 +40,15 @@ blocks: - type: item item: default:honeydew_item functions: + - type: set_count + add: false + count: 3~7 - type: apply_bonus enchantment: minecraft:fortune formula: type: ore_drops - - type: set_count - add: false - count: 3~7 + - type: limit_count + max: 9 - type: explosion_decay settings: map-color: 19 diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/LimitCountFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LimitCountFunction.java new file mode 100644 index 000000000..8ecc4fc2b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/LimitCountFunction.java @@ -0,0 +1,65 @@ +package net.momirealms.craftengine.core.loot.function; + +import net.momirealms.craftengine.core.item.Item; +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.number.NumberProvider; +import net.momirealms.craftengine.core.plugin.context.number.NumberProviders; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class LimitCountFunction extends AbstractLootConditionalFunction { + public static final Factory FACTORY = new Factory<>(); + @Nullable + private final NumberProvider min; + @Nullable + private final NumberProvider max; + + public LimitCountFunction(List> predicates, @Nullable NumberProvider min, @Nullable NumberProvider max) { + super(predicates); + this.min = min; + this.max = max; + } + + @Override + public Key type() { + return LootFunctions.LIMIT_COUNT; + } + + @Override + protected Item applyInternal(Item item, LootContext context) { + int amount = item.count(); + if (min != null) { + int minAmount = min.getInt(context); + if (amount < minAmount) { + item.count(minAmount); + } + } + if (max != null) { + int maxAmount = max.getInt(context); + if (amount > maxAmount) { + item.count(maxAmount); + } + } + return item; + } + + public static class Factory implements LootFunctionFactory { + @SuppressWarnings("unchecked") + @Override + public LootFunction create(Map arguments) { + Object min = arguments.get("min"); + Object max = arguments.get("max"); + List> conditions = Optional.ofNullable(arguments.get("conditions")) + .map(it -> LootConditions.fromMapList((List>) it)) + .orElse(Collections.emptyList()); + return new LimitCountFunction<>(conditions, min == null ? null : NumberProviders.fromObject(min), max == null ? null : NumberProviders.fromObject(max)); + } + } +} 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 c2233c20f..c9d221c95 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 @@ -20,12 +20,14 @@ public class LootFunctions { public static final Key SET_COUNT = Key.from("craftengine:set_count"); public static final Key EXPLOSION_DECAY = Key.from("craftengine:explosion_decay"); public static final Key DROP_EXP = Key.from("craftengine:drop_exp"); + public static final Key LIMIT_COUNT = Key.from("craftengine:limit_count"); static { register(SET_COUNT, SetCountFunction.FACTORY); register(EXPLOSION_DECAY, ExplosionDecayFunction.FACTORY); register(APPLY_BONUS, ApplyBonusCountFunction.FACTORY); register(DROP_EXP, DropExpFunction.FACTORY); + register(LIMIT_COUNT, LimitCountFunction.FACTORY); } public static void register(Key key, LootFunctionFactory factory) { From 9480737b84efc58cf081ea8f10738d791eb4951d Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Tue, 23 Sep 2025 18:27:03 +0800 Subject: [PATCH 046/125] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=93=88=E5=AF=86?= =?UTF-8?q?=E7=93=9C=E9=85=8D=E7=BD=AE=E5=92=8C=E7=9B=B8=E5=85=B3=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../behavior/AttachedStemBlockBehavior.java | 27 +- .../block/behavior/GrassBlockBehavior.java | 2 +- .../block/behavior/SaplingBlockBehavior.java | 2 +- .../block/behavior/StemBlockBehavior.java | 21 +- .../UnsafeCompositeBlockBehavior.java | 10 - .../plugin/injector/BlockGenerator.java | 18 -- .../reflection/minecraft/CoreReflections.java | 10 - .../configuration/blocks/hami_melon.yml | 230 ++++++++++++++ .../default/configuration/blocks/honeydew.yml | 298 ------------------ .../default/configuration/categories.yml | 5 +- .../resources/default/configuration/i18n.yml | 22 +- .../custom/{honeydew.png => hami_melon.png} | Bin ...eydew_bottom.png => hami_melon_bottom.png} | Bin .../{honeydew_top.png => hami_melon_top.png} | Bin .../textures/item/custom/hami_melon_seeds.png | Bin 0 -> 340 bytes ...honeydew_item.png => hami_melon_slice.png} | Bin .../craftengine/core/block/BlockBehavior.java | 6 - .../core/pack/AbstractPackManager.java | 11 +- gradle.properties | 4 +- 19 files changed, 266 insertions(+), 400 deletions(-) create mode 100644 common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml delete mode 100644 common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml rename common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/{honeydew.png => hami_melon.png} (100%) rename common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/{honeydew_bottom.png => hami_melon_bottom.png} (100%) rename common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/{honeydew_top.png => hami_melon_top.png} (100%) create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_seeds.png rename common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/{honeydew_item.png => hami_melon_slice.png} (100%) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java index 1e30aafb9..f35d35159 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/AttachedStemBlockBehavior.java @@ -11,40 +11,31 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.util.HorizontalDirection; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.util.VersionHelper; -import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.Callable; -public class AttachedStemBlockBehavior extends BushBlockBehavior { +public class AttachedStemBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final Property facingProperty; private final Key fruit; private final Key stem; public AttachedStemBlockBehavior(CustomBlock customBlock, - int delay, - boolean blacklist, - List tagsCanSurviveOn, - Set blockStatesCanSurviveOn, - Set customBlocksCansSurviveOn, Property facingProperty, Key fruit, Key stem) { - super(customBlock, delay, blacklist, false, tagsCanSurviveOn, blockStatesCanSurviveOn, customBlocksCansSurviveOn); + super(customBlock); this.facingProperty = facingProperty; this.fruit = fruit; this.stem = stem; } - @Override - public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) { - return FastNMS.INSTANCE.field$FluidState$isEmpty(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(args[0])); - } - @Override public boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) throws Exception { return (VersionHelper.isOrAbove1_20_5() ? args[1] : args[3]).equals(CoreReflections.instance$PathComputationType$AIR) @@ -97,14 +88,12 @@ public class AttachedStemBlockBehavior extends BushBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - Tuple, Set, Set> tuple = readTagsAndState(arguments, false); - int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); - boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist"); + @SuppressWarnings("unchecked") Property facingProperty = (Property) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("facing"), "warning.config.block.behavior.attached_stem.missing_facing"); Key fruit = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("fruit"), "warning.config.block.behavior.attached_stem.missing_fruit")); Key stem = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("stem"), "warning.config.block.behavior.attached_stem.missing_stem")); - return new AttachedStemBlockBehavior(block, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), facingProperty, fruit, stem); + return new AttachedStemBlockBehavior(block, facingProperty, fruit, stem); } } } 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 20833c67c..6903885ef 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 @@ -146,7 +146,7 @@ public class GrassBlockBehavior extends BukkitBlockBehavior { } if (FastNMS.INSTANCE.method$BlockStateBase$isAir(currentState)) { Object chunkGenerator = CoreReflections.method$ServerChunkCache$getGenerator.invoke(FastNMS.INSTANCE.method$ServerLevel$getChunkSource(world)); - Object placedFeature = CoreReflections.method$Holder$value.invoke(holder.get()); + Object placedFeature = FastNMS.INSTANCE.method$Holder$value(holder.get()); CoreReflections.method$PlacedFeature$place.invoke(placedFeature, world, chunkGenerator, random, nmsCurrentPos); } } 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 c56fa4050..fa3535e88 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 @@ -88,7 +88,7 @@ public class SaplingBlockBehavior extends BukkitBlockBehavior { return; } Object chunkGenerator = CoreReflections.method$ServerChunkCache$getGenerator.invoke(FastNMS.INSTANCE.method$ServerLevel$getChunkSource(world)); - Object configuredFeature = CoreReflections.method$Holder$value.invoke(holder.get()); + Object configuredFeature = FastNMS.INSTANCE.method$Holder$value(holder.get()); 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()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java index d7d1180c3..69755b7ac 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StemBlockBehavior.java @@ -17,13 +17,11 @@ import net.momirealms.craftengine.core.block.properties.IntegerProperty; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.util.*; -import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.concurrent.Callable; -public class StemBlockBehavior extends BushBlockBehavior { +public class StemBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final IntegerProperty ageProperty; private final Key fruit; @@ -33,18 +31,13 @@ public class StemBlockBehavior extends BushBlockBehavior { private final Object blockMayPlaceFruit; public StemBlockBehavior(CustomBlock customBlock, - int delay, - boolean blacklist, - List tagsCanSurviveOn, - Set blockStatesCanSurviveOn, - Set customBlocksCansSurviveOn, IntegerProperty ageProperty, Key fruit, Key attachedStem, int minGrowLight, Object tagMayPlaceFruit, Object blockMayPlaceFruit) { - super(customBlock, delay, blacklist, false, tagsCanSurviveOn, blockStatesCanSurviveOn, customBlocksCansSurviveOn); + super(customBlock); this.ageProperty = ageProperty; this.fruit = fruit; this.attachedStem = attachedStem; @@ -53,11 +46,6 @@ public class StemBlockBehavior extends BushBlockBehavior { this.blockMayPlaceFruit = blockMayPlaceFruit; } - @Override - public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) { - return FastNMS.INSTANCE.field$FluidState$isEmpty(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(args[0])); - } - @Override public boolean isPathFindable(Object thisBlock, Object[] args, Callable superMethod) throws Exception { return (VersionHelper.isOrAbove1_20_5() ? args[1] : args[3]).equals(CoreReflections.instance$PathComputationType$AIR) @@ -139,16 +127,13 @@ public class StemBlockBehavior extends BushBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - Tuple, Set, Set> tuple = readTagsAndState(arguments, false); - int delay = ResourceConfigUtils.getAsInt(arguments.getOrDefault("delay", 0), "delay"); - boolean blacklistMode = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("blacklist", false), "blacklist"); IntegerProperty ageProperty = (IntegerProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("age"), "warning.config.block.behavior.stem.missing_age"); Key fruit = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("fruit"), "warning.config.block.behavior.stem.missing_fruit")); Key attachedStem = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("attached-stem"), "warning.config.block.behavior.stem.missing_attached_stem")); int minGrowLight = ResourceConfigUtils.getAsInt(arguments.getOrDefault("light-requirement", 9), "light-requirement"); Object tagMayPlaceFruit = FastNMS.INSTANCE.method$TagKey$create(MRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("may-place-fruit", "minecraft:dirt").toString()))); Object blockMayPlaceFruit = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(Key.of(arguments.getOrDefault("may-place-fruit", "minecraft:farmland").toString()))); - return new StemBlockBehavior(block, delay, blacklistMode, tuple.left(), tuple.mid(), tuple.right(), ageProperty, fruit, attachedStem, minGrowLight, tagMayPlaceFruit, blockMayPlaceFruit); + return new StemBlockBehavior(block, ageProperty, fruit, attachedStem, minGrowLight, tagMayPlaceFruit, blockMayPlaceFruit); } } } 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 8e9e4c631..0aab207be 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 @@ -381,14 +381,4 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior } FallOnBlockBehavior.super.updateEntityMovementAfterFallOn(thisBlock, args, superMethod); } - - @Override - public boolean propagatesSkylightDown(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - for (AbstractBlockBehavior behavior : this.behaviors) { - if (!behavior.propagatesSkylightDown(thisBlock, args, superMethod)) { - return false; - } - } - return (boolean) superMethod.call(); - } } 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 d54835999..ae5e8c670 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 @@ -170,9 +170,6 @@ public final class BlockGenerator { // stepOn .method(ElementMatchers.is(CoreReflections.method$Block$stepOn)) .intercept(MethodDelegation.to(StepOnInterceptor.INSTANCE)) - // propagatesSkylightDown - .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$propagatesSkylightDown)) - .intercept(MethodDelegation.to(PropagatesSkylightDownInterceptor.INSTANCE)) ; // 1.21.5+ if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) { @@ -763,19 +760,4 @@ public final class BlockGenerator { } } } - - public static class PropagatesSkylightDownInterceptor { - public static final PropagatesSkylightDownInterceptor INSTANCE = new PropagatesSkylightDownInterceptor(); - - @RuntimeType - public boolean intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { - ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); - try { - return holder.value().propagatesSkylightDown(thisObj, args, superMethod); - } catch (Exception e) { - CraftEngine.instance().logger().severe("Failed to run propagatesSkylightDown", e); - return false; - } - } - } } \ No newline at end of file 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 f4b0439d1..0cae0070e 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 @@ -4418,14 +4418,4 @@ public final class CoreReflections { public static final Method method$BlockStateBase$isBlock = requireNonNull( ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Block) ); - - public static final Method method$BlockBehaviour$propagatesSkylightDown = requireNonNull( - VersionHelper.isOrAbove1_21_2() - ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "e_"}, clazz$BlockState) - : VersionHelper.isOrAbove1_20_5() - ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) - : VersionHelper.isOrAbove1_20_4() - ? ReflectionUtils.getDeclaredMethod(clazz$Block, boolean.class, new String[]{"propagatesSkylightDown", "a_"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) - : ReflectionUtils.getDeclaredMethod(clazz$Block, boolean.class, new String[]{"propagatesSkylightDown", "c"}, clazz$BlockState, clazz$BlockGetter, clazz$BlockPos) - ); } diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml new file mode 100644 index 000000000..dd2b70a6e --- /dev/null +++ b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml @@ -0,0 +1,230 @@ +items: + default:hami_melon_slice: + material: melon_slice + custom-model-data: 1000 + data: + item-name: + $$>=1.20.5: + food: + nutrition: 2 + saturation: 1.0 + can-always-eat: false + $$<=1.20.4: + settings: + food: + nutrition: 2 + saturation: 1.0 + model: + template: default:model/simplified_generated + arguments: + path: minecraft:item/custom/hami_melon_slice + default:hami_melon: + material: nether_brick + custom-model-data: 3023 + data: + item-name: + model: + path: minecraft:item/custom/hami_melon + generation: + parent: minecraft:block/custom/hami_melon + behavior: + type: block_item + block: default:hami_melon + default:hami_melon_seeds: + material: nether_brick + custom-model-data: 3024 + data: + item-name: + model: + template: default:model/simplified_generated + arguments: + path: minecraft:item/custom/hami_melon_seeds + behavior: + type: block_item + block: default:hami_melon_stem +blocks: + default:hami_melon: + loot: + pools: + - rolls: 1 + entries: + - type: alternatives + children: + - type: item + item: default:hami_melon + conditions: + - type: enchantment + predicate: minecraft:silk_touch>=1 + - type: item + item: default:hami_melon_slice + functions: + - type: set_count + add: false + count: 3~7 + - type: apply_bonus + enchantment: minecraft:fortune + formula: + type: ore_drops + - type: limit_count + max: 9 + - type: explosion_decay + settings: + map-color: 19 + hardness: 1 + resistance: 1 + push-reaction: DESTROY + is-suffocating: true + is-redstone-conductor: true + tags: + - minecraft:enderman_holdable + - minecraft:mineable/axe + - minecraft:sword_efficient + state: + id: 30 + state: note_block:30 + model: + template: default:model/cube + arguments: + model: minecraft:block/custom/hami_melon + particle_texture: minecraft:block/custom/hami_melon + down_texture: minecraft:block/custom/hami_melon_bottom + up_texture: minecraft:block/custom/hami_melon_top + north_texture: minecraft:block/custom/hami_melon + east_texture: minecraft:block/custom/hami_melon + south_texture: minecraft:block/custom/hami_melon + west_texture: minecraft:block/custom/hami_melon + default:hami_melon_stem: + settings: + map-color: 7 + hardness: 0 + resistance: 0 + push-reaction: DESTROY + is-suffocating: false + is-redstone-conductor: false + item: default:hami_melon_item + is-randomly-ticking: true + tags: + - minecraft:bee_growables + - minecraft:crops + - minecraft:maintains_farmland + behaviors: + - type: stem_block + fruit: default:hami_melon + attached-stem: default:attached_hami_melon_stem + - type: bush_block + bottom-blocks: + - minecraft:farmland + states: + properties: + age: + type: int + default: 0 + range: 0~7 + appearances: + age=0: + state: pumpkin_stem[age=0] + age=1: + state: pumpkin_stem[age=1] + age=2: + state: pumpkin_stem[age=2] + age=3: + state: pumpkin_stem[age=3] + age=4: + state: pumpkin_stem[age=4] + age=5: + state: pumpkin_stem[age=5] + age=6: + state: pumpkin_stem[age=6] + age=7: + state: pumpkin_stem[age=7] + variants: + age=0: + appearance: age=0 + id: 0 + age=1: + appearance: age=1 + id: 1 + age=2: + appearance: age=2 + id: 2 + age=3: + appearance: age=3 + id: 3 + age=4: + appearance: age=4 + id: 4 + age=5: + appearance: age=5 + id: 5 + age=6: + appearance: age=6 + id: 6 + age=7: + appearance: age=7 + id: 7 + default:attached_hami_melon_stem: + settings: + map-color: 7 + hardness: 0 + resistance: 0 + push-reaction: DESTROY + is-suffocating: false + is-redstone-conductor: false + item: default:hami_melon_seeds + is-randomly-ticking: true + tags: + - minecraft:maintains_farmland + behaviors: + - type: attached_stem_block + fruit: default:hami_melon + stem: default:hami_melon_stem + - type: bush_block + blacklist: false + bottom-blocks: + - minecraft:farmland + states: + properties: + facing: + type: horizontal_direction + default: north + appearances: + facing=east: + state: attached_pumpkin_stem[facing=east] + facing=south: + state: attached_pumpkin_stem[facing=south] + facing=west: + state: attached_pumpkin_stem[facing=west] + facing=north: + state: attached_pumpkin_stem[facing=north] + variants: + facing=east: + appearance: facing=east + id: 0 + facing=south: + appearance: facing=south + id: 1 + facing=west: + appearance: facing=west + id: 2 + facing=north: + appearance: facing=north + id: 3 +recipes: + default:hami_melon: + type: shaped + pattern: + - AAA + - AAA + - AAA + ingredients: + A: default:hami_melon_slice + result: + id: default:hami_melon + count: 1 + default:hami_melon_seeds: + type: shapeless + ingredients: + - default:hami_melon_slice + result: + id: default:hami_melon_seeds + count: 1 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml b/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml deleted file mode 100644 index 0291afcbe..000000000 --- a/common-files/src/main/resources/resources/default/configuration/blocks/honeydew.yml +++ /dev/null @@ -1,298 +0,0 @@ -items: - default:honeydew_item: - material: apple - custom-model-data: 1000 - data: - item-name: - model: - template: default:model/simplified_generated - arguments: - path: minecraft:item/custom/honeydew_item - behavior: - type: block_item - block: default:honeydew_stem - default:honeydew: - material: nether_brick - custom-model-data: 3023 - data: - item-name: - model: - path: minecraft:item/custom/honeydew - generation: - parent: minecraft:block/custom/honeydew - behavior: - type: block_item - block: default:honeydew - -blocks: - default:honeydew: - loot: - pools: - - rolls: 1 - entries: - - type: alternatives - children: - - type: item - item: default:honeydew - conditions: - - type: enchantment - predicate: minecraft:silk_touch>=1 - - type: item - item: default:honeydew_item - functions: - - type: set_count - add: false - count: 3~7 - - type: apply_bonus - enchantment: minecraft:fortune - formula: - type: ore_drops - - type: limit_count - max: 9 - - type: explosion_decay - settings: - map-color: 19 - hardness: 1 - resistance: 1 - push-reaction: DESTROY - is-suffocating: true - is-redstone-conductor: true - item: default:honeydew - tags: - - minecraft:enderman_holdable - - minecraft:mineable/axe - - minecraft:sword_efficient - incorrect-tool-dig-speed: 1 - state: - id: 30 - state: note_block:30 - model: - template: default:model/cube - arguments: - model: minecraft:block/custom/honeydew - particle_texture: minecraft:block/custom/honeydew - down_texture: minecraft:block/custom/honeydew_bottom - up_texture: minecraft:block/custom/honeydew_top - north_texture: minecraft:block/custom/honeydew - east_texture: minecraft:block/custom/honeydew - south_texture: minecraft:block/custom/honeydew - west_texture: minecraft:block/custom/honeydew - default:honeydew_stem: - loot: - pools: - - rolls: 1 - entries: - - type: item - item: default:honeydew_item - functions: - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 0 - count: - type: binomial - extra: 3 - probability: 0.06666667 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 1 - count: - type: binomial - extra: 3 - probability: 0.13333334 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 2 - count: - type: binomial - extra: 3 - probability: 0.2 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 3 - count: - type: binomial - extra: 3 - probability: 0.26666668 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 4 - count: - type: binomial - extra: 3 - probability: 0.33333334 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 5 - count: - type: binomial - extra: 3 - probability: 0.4 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 6 - count: - type: binomial - extra: 3 - probability: 0.46666667 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 7 - count: - type: binomial - extra: 3 - probability: 0.53333336 - functions: - - type: explosion_decay - settings: - map-color: 7 - hardness: 0 - resistance: 0 - push-reaction: DESTROY - is-suffocating: false - is-redstone-conductor: false - item: default:honeydew_item - is-randomly-ticking: true - tags: - - minecraft:bee_growables - - minecraft:crops - - minecraft:maintains_farmland - behaviors: - type: stem_block - fruit: default:honeydew - attached-stem: default:attached_honeydew_stem - blacklist: false - bottom-blocks: - - minecraft:farmland - states: - properties: - age: - type: int - default: 0 - range: 0~7 - appearances: - age=0: - state: pumpkin_stem[age=0] - age=1: - state: pumpkin_stem[age=1] - age=2: - state: pumpkin_stem[age=2] - age=3: - state: pumpkin_stem[age=3] - age=4: - state: pumpkin_stem[age=4] - age=5: - state: pumpkin_stem[age=5] - age=6: - state: pumpkin_stem[age=6] - age=7: - state: pumpkin_stem[age=7] - variants: - age=0: - appearance: age=0 - id: 0 - age=1: - appearance: age=1 - id: 1 - age=2: - appearance: age=2 - id: 2 - age=3: - appearance: age=3 - id: 3 - age=4: - appearance: age=4 - id: 4 - age=5: - appearance: age=5 - id: 5 - age=6: - appearance: age=6 - id: 6 - age=7: - appearance: age=7 - id: 7 - default:attached_honeydew_stem: - loot: - pools: - - rolls: 1 - entries: - - type: item - item: default:honeydew_item - functions: - - type: set_count - add: false - count: - type: binomial - extra: 3 - probability: 0.53333336 - functions: - - type: explosion_decay - settings: - map-color: 7 - hardness: 0 - resistance: 0 - push-reaction: DESTROY - is-suffocating: false - is-redstone-conductor: false - item: default:honeydew_item - is-randomly-ticking: true - tags: - - minecraft:maintains_farmland - behaviors: - type: attached_stem_block - fruit: default:honeydew - stem: default:honeydew_stem - blacklist: false - bottom-blocks: - - minecraft:farmland - states: - properties: - facing: - type: horizontal_direction - default: north - appearances: - facing=east: - state: attached_pumpkin_stem[facing=east] - facing=south: - state: attached_pumpkin_stem[facing=south] - facing=west: - state: attached_pumpkin_stem[facing=west] - facing=north: - state: attached_pumpkin_stem[facing=north] - variants: - facing=east: - appearance: facing=east - id: 0 - facing=south: - appearance: facing=south - id: 1 - facing=west: - appearance: facing=west - id: 2 - facing=north: - appearance: facing=north - id: 3 diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 6f02cfd78..7719dacfe 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -79,5 +79,6 @@ categories: - default:wooden_chair - default:flower_basket - default:amethyst_torch - - default:honeydew_item - - default:honeydew \ No newline at end of file + - default:hami_melon_seeds + - default:hami_melon_slice + - default:hami_melon \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index fbd75318d..df4fa5f14 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -49,8 +49,9 @@ i18n: item.safe_block: Safe Block item.sofa: Sofa item.amethyst_torch: Amethyst Torch - item.honeydew_item: Honeydew Slice - item.honeydew: Honeydew + item.hami_melon_slice: Hami Melon Slice + item.hami_melon: Hami Melon + item.hami_melon_seeds: Hami Melon Seeds category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -109,8 +110,9 @@ i18n: item.safe_block: 保险柜 item.sofa: 沙发 item.amethyst_torch: 紫水晶火把 - item.honeydew_item: 哈密瓜片 - item.honeydew: 哈密瓜 + item.hami_melon_slice: 哈密瓜片 + item.hami_melon: 哈密瓜 + item.hami_melon_seeds: 哈密瓜种子 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 @@ -153,9 +155,9 @@ lang: block_name:default:sofa: Sofa block_name:default:amethyst_torch: Amethyst Torch block_name:default:amethyst_wall_torch: Amethyst Torch - block_name:default:honeydew: Honeydew - block_name:default:honeydew_stem: Honeydew Stem - block_name:default:default:attached_honeydew_stem: Honeydew Stem + block_name:default:hami_melon: Hami Melon + block_name:default:hami_melon_stem: Hami Melon Stem + block_name:default:default:attached_hami_melon_stem: Hami Melon Stem zh_cn: block_name:default:chinese_lantern: 灯笼 block_name:default:netherite_anvil: 下界合金砧 @@ -186,6 +188,6 @@ lang: block_name:default:sofa: 沙发 block_name:default:amethyst_torch: 紫水晶火把 block_name:default:amethyst_wall_torch: 紫水晶火把 - block_name:default:honeydew: 哈密瓜 - block_name:default:honeydew_stem: 哈密瓜茎 - block_name:default:default:attached_honeydew_stem: 哈密瓜茎 \ No newline at end of file + block_name:default:hami_melon: 哈密瓜 + block_name:default:hami_melon_stem: 哈密瓜茎 + block_name:default:default:attached_hami_melon_stem: 哈密瓜茎 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon.png similarity index 100% rename from common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png rename to common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon.png diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon_bottom.png similarity index 100% rename from common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png rename to common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon_bottom.png diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon_top.png similarity index 100% rename from common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png rename to common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon_top.png diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_seeds.png b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_seeds.png new file mode 100644 index 0000000000000000000000000000000000000000..74c7165ec69c1407810bb7cffdc7ffce02d58465 GIT binary patch literal 340 zcmV-a0jvIrP)Px$4oO5oR5*=eV4x5%ViR!0BWMD+PuPyRO4s!h%n8PaOvX0|NuY)9e2kq%|2CCeP=BxdOKrU>cuZ z{}0!^?gTdj!wCk4SFb)XJb(L{fuI+V{m;Mv(FgGbqaPp@ck)4OfR06D-&?!$4LsF9QPuFGJk!ZwwZf{$dL*1}3bc zP|f#tJYsnF=sQYy5N*J_N8cF)v_u&SZvJNw-};_`ftWC0K=O0JO-MANYbF?t`kK;k mKDv$QnlTJuATc9R1poj?yN}oU`=w9-0000 superMethod) throws Exception { - return (boolean) superMethod.call(); - } - public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; } 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 b3eafb708..586931ea7 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 @@ -431,7 +431,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/configuration/blocks/topaz_ore.yml"); plugin.saveResource("resources/default/configuration/blocks/netherite_anvil.yml"); plugin.saveResource("resources/default/configuration/blocks/amethyst_torch.yml"); - plugin.saveResource("resources/default/configuration/blocks/honeydew.yml"); + plugin.saveResource("resources/default/configuration/blocks/hami_melon.yml"); // assets plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/font/image/emojis.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/chinese_lantern.png"); @@ -538,10 +538,11 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_background.png.mcmeta"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png.mcmeta"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_bottom.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/honeydew_top.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/honeydew_item.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon_bottom.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon_top.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_slice.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_seeds.png"); } private TreeMap> updateCachedConfigFiles() { diff --git a/gradle.properties b/gradle.properties index 1aa561ed6..5cae0308f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.4 +project_version=0.0.63.5 config_version=46 lang_version=31 project_group=net.momirealms @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.94 +nms_helper_version=1.0.95 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1 From f8a1d7a704fd928aadd7a3d95cddf507fdda0599 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 06:40:31 +0800 Subject: [PATCH 047/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/resources/additional-real-blocks.yml | 3 +- .../configuration/blocks/hami_melon.yml | 106 +- .../configuration/blocks/palm_tree.yml | 1175 +++++++++++------ .../default/configuration/categories.yml | 1 + .../resources/default/configuration/i18n.yml | 6 +- 5 files changed, 868 insertions(+), 423 deletions(-) diff --git a/common-files/src/main/resources/additional-real-blocks.yml b/common-files/src/main/resources/additional-real-blocks.yml index 98472f7de..31bea6787 100644 --- a/common-files/src/main/resources/additional-real-blocks.yml +++ b/common-files/src/main/resources/additional-real-blocks.yml @@ -86,4 +86,5 @@ minecraft:white_bed: 1 minecraft:redstone_torch: 1 minecraft:redstone_wall_torch: 4 minecraft:pumpkin_stem: 8 -minecraft:attached_pumpkin_stem: 4 \ No newline at end of file +minecraft:attached_pumpkin_stem: 4 +minecraft:birch_button: 24 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml index dd2b70a6e..3d2cb6e37 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml @@ -94,6 +94,95 @@ blocks: south_texture: minecraft:block/custom/hami_melon west_texture: minecraft:block/custom/hami_melon default:hami_melon_stem: + loot: + pools: + - rolls: 1 + entries: + - type: item + item: default:hami_melon_seeds + functions: + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 0 + count: + type: binomial + extra: 3 + probability: 0.06666667 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 1 + count: + type: binomial + extra: 3 + probability: 0.13333334 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 2 + count: + type: binomial + extra: 3 + probability: 0.2 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 3 + count: + type: binomial + extra: 3 + probability: 0.26666668 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 4 + count: + type: binomial + extra: 3 + probability: 0.33333334 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 5 + count: + type: binomial + extra: 3 + probability: 0.4 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 6 + count: + type: binomial + extra: 3 + probability: 0.46666667 + - type: set_count + add: false + conditions: + - type: match_block_property + properties: + age: 7 + count: + type: binomial + extra: 3 + probability: 0.53333336 + functions: + - type: explosion_decay settings: map-color: 7 hardness: 0 @@ -101,7 +190,7 @@ blocks: push-reaction: DESTROY is-suffocating: false is-redstone-conductor: false - item: default:hami_melon_item + item: default:hami_melon_seeds is-randomly-ticking: true tags: - minecraft:bee_growables @@ -163,6 +252,21 @@ blocks: appearance: age=7 id: 7 default:attached_hami_melon_stem: + loot: + pools: + - rolls: 1 + entries: + - type: item + item: default:hami_melon_seeds + functions: + - type: set_count + add: false + count: + type: binomial + extra: 3 + probability: 0.53333336 + functions: + - type: explosion_decay settings: map-color: 7 hardness: 0 diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index fe8e46bd6..7e935d5d5 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -17,30 +17,7 @@ items: parent: minecraft:block/custom/palm_log behavior: type: block_item - block: - behavior: - type: strippable_block - stripped: default:stripped_palm_log - loot: - template: default:loot_table/self - settings: - template: default:settings/wood - states: - template: default:block_state/pillar - arguments: - base_block: note_block - texture_top_path: minecraft:block/custom/palm_log_top - texture_side_path: minecraft:block/custom/palm_log - model_vertical_path: minecraft:block/custom/palm_log - model_horizontal_path: minecraft:block/custom/palm_log_horizontal - vanilla_id: - type: self_increase_int - from: 0 - to: 2 - internal_id: - type: self_increase_int - from: 0 - to: 2 + block: default:palm_log default:stripped_palm_log: material: nether_brick custom-model-data: 1001 @@ -59,27 +36,7 @@ items: parent: minecraft:block/custom/stripped_palm_log behavior: type: block_item - block: - loot: - template: default:loot_table/self - settings: - template: default:settings/wood - states: - template: default:block_state/pillar - arguments: - base_block: note_block - texture_top_path: minecraft:block/custom/stripped_palm_log_top - texture_side_path: minecraft:block/custom/stripped_palm_log - model_vertical_path: minecraft:block/custom/stripped_palm_log - model_horizontal_path: minecraft:block/custom/stripped_palm_log_horizontal - vanilla_id: - type: self_increase_int - from: 3 - to: 5 - internal_id: - type: self_increase_int - from: 3 - to: 5 + block: default:stripped_palm_log default:palm_wood: material: nether_brick custom-model-data: 1002 @@ -98,30 +55,7 @@ items: parent: minecraft:block/custom/palm_wood behavior: type: block_item - block: - behavior: - type: strippable_block - stripped: default:stripped_palm_wood - loot: - template: default:loot_table/self - settings: - template: default:settings/wood - states: - template: default:block_state/pillar - arguments: - base_block: note_block - texture_top_path: minecraft:block/custom/palm_log - texture_side_path: minecraft:block/custom/palm_log - model_vertical_path: minecraft:block/custom/palm_wood - model_horizontal_path: minecraft:block/custom/palm_wood_horizontal - vanilla_id: - type: self_increase_int - from: 6 - to: 8 - internal_id: - type: self_increase_int - from: 6 - to: 8 + block: default:palm_wood default:stripped_palm_wood: material: nether_brick custom-model-data: 1003 @@ -140,27 +74,7 @@ items: parent: minecraft:block/custom/stripped_palm_wood behavior: type: block_item - block: - loot: - template: default:loot_table/self - settings: - template: default:settings/wood - states: - template: default:block_state/pillar - arguments: - base_block: note_block - texture_top_path: minecraft:block/custom/stripped_palm_log - texture_side_path: minecraft:block/custom/stripped_palm_log - model_vertical_path: minecraft:block/custom/stripped_palm_wood - model_horizontal_path: minecraft:block/custom/stripped_palm_wood_horizontal - vanilla_id: - type: self_increase_int - from: 9 - to: 11 - internal_id: - type: self_increase_int - from: 9 - to: 11 + block: default:stripped_palm_wood default:palm_planks: material: nether_brick custom-model-data: 1004 @@ -178,18 +92,7 @@ items: parent: minecraft:block/custom/palm_planks behavior: type: block_item - block: - settings: - template: default:settings/planks - loot: - template: default:loot_table/self - state: - model: - template: default:model/simplified_cube_all - arguments: - path: minecraft:block/custom/palm_planks - id: 12 - state: note_block:12 + block: default:palm_planks default:palm_sapling: material: nether_brick custom-model-data: 1005 @@ -204,42 +107,7 @@ items: texture: minecraft:block/custom/palm_sapling behavior: type: block_item - block: - settings: - template: default:settings/sapling - behaviors: - - type: bush_block - bottom-block-tags: - - minecraft:dirt - - minecraft:farmland - - minecraft:sand - - type: sapling_block - feature: minecraft:fancy_oak - bone-meal-success-chance: 0.45 - loot: - template: default:loot_table/self - states: - properties: - stage: - type: int - default-value: 0 - range: 0~1 - appearances: - default: - state: oak_sapling:0 - model: - path: minecraft:block/custom/palm_sapling - generation: - parent: minecraft:block/cross - textures: - cross: minecraft:block/custom/palm_sapling - variants: - stage=0: - appearance: default - id: 0 - stage=1: - appearance: default - id: 1 + block: default:palm_sapling default:palm_leaves: material: oak_leaves custom-model-data: 1000 @@ -247,9 +115,9 @@ items: item-name: components: minecraft:block_state: - distance: '1' - persistent: 'false' - waterlogged: 'false' + distance: "1" + persistent: "false" + waterlogged: "false" model: type: minecraft:model path: minecraft:item/custom/palm_leaves @@ -260,27 +128,7 @@ items: value: -12012264 behavior: type: block_item - block: - behavior: - type: leaves_block - loot: - template: default:loot_table/leaves - arguments: - leaves: default:palm_leaves - sapling: default:palm_sapling - settings: - template: default:settings/leaves - states: - template: default:block_state/leaves - arguments: - default_state: oak_leaves[distance=1,persistent=false,waterlogged=false] - waterlogged_state: oak_leaves[distance=1,persistent=false,waterlogged=true] - model_path: minecraft:block/custom/palm_leaves - texture_path: minecraft:block/custom/palm_leaves - internal_id: - type: self_increase_int - from: 0 - to: 27 + block: default:palm_leaves default:palm_trapdoor: material: nether_brick custom-model-data: 1006 @@ -295,47 +143,7 @@ items: parent: minecraft:block/custom/palm_trapdoor_bottom behavior: type: block_item - block: - behavior: - type: trapdoor_block - can-open-with-hand: true - can-open-by-wind-charge: true - sounds: - open: minecraft:block.wooden_trapdoor.open - close: minecraft:block.wooden_trapdoor.close - loot: - template: default:loot_table/self - settings: - template: - - default:sound/wood - overrides: - map-color: 2 - instrument: bass - hardness: 3.0 - resistance: 3.0 - burnable: true - tags: - - minecraft:mineable/axe - - minecraft:trapdoors - states: - template: default:block_state/trapdoor - arguments: - base_block: acacia_trapdoor - model_bottom_path: minecraft:block/custom/palm_trapdoor_bottom - model_bottom_generation: - parent: minecraft:block/template_orientable_trapdoor_bottom - textures: - texture: minecraft:block/custom/palm_trapdoor - model_open_path: minecraft:block/custom/palm_trapdoor_open - model_open_generation: - parent: minecraft:block/template_orientable_trapdoor_open - textures: - texture: minecraft:block/custom/palm_trapdoor - model_top_path: minecraft:block/custom/palm_trapdoor_top - model_top_generation: - parent: minecraft:block/template_orientable_trapdoor_top - textures: - texture: minecraft:block/custom/palm_trapdoor + block: default:palm_trapdoor default:palm_door: material: nether_brick custom-model-data: 1007 @@ -349,68 +157,7 @@ items: path: minecraft:item/custom/palm_door behavior: type: double_high_block_item - block: - behavior: - type: door_block - can-open-with-hand: true - can-open-by-wind-charge: true - sounds: - open: minecraft:block.wooden_door.open - close: minecraft:block.wooden_door.close - loot: - template: default:loot_table/door - settings: - template: - - default:sound/wood - overrides: - push-reaction: destroy - map-color: 2 - instrument: bass - hardness: 3.0 - resistance: 3.0 - burnable: true - tags: - - minecraft:wooden_doors - - minecraft:doors - - minecraft:mineable/axe - states: - template: default:block_state/door - arguments: - base_block: oak_door - model_top_left_path: minecraft:block/custom/palm_door_top_left - model_top_left_generation: - parent: minecraft:block/door_top_left - textures: &textures - bottom: minecraft:block/custom/palm_door_bottom - top: minecraft:block/custom/palm_door_top - model_top_right_path: minecraft:block/custom/palm_door_top_right - model_top_right_generation: - parent: minecraft:block/door_top_right - textures: *textures - model_top_left_open_path: minecraft:block/custom/palm_door_top_left_open - model_top_left_open_generation: - parent: minecraft:block/door_top_left_open - textures: *textures - model_top_right_open_path: minecraft:block/custom/palm_door_top_right_open - model_top_right_open_generation: - parent: minecraft:block/door_top_right_open - textures: *textures - model_bottom_left_path: minecraft:block/custom/palm_door_bottom_left - model_bottom_left_generation: - parent: minecraft:block/door_bottom_left - textures: *textures - model_bottom_right_path: minecraft:block/custom/palm_door_bottom_right - model_bottom_right_generation: - parent: minecraft:block/door_bottom_right - textures: *textures - model_bottom_left_open_path: minecraft:block/custom/palm_door_bottom_left_open - model_bottom_left_open_generation: - parent: minecraft:block/door_bottom_left_open - textures: *textures - model_bottom_right_open_path: minecraft:block/custom/palm_door_bottom_right_open - model_bottom_right_open_generation: - parent: minecraft:block/door_bottom_right_open - textures: *textures + block: default:palm_door default:palm_fence_gate: material: nether_brick custom-model-data: 1008 @@ -425,49 +172,7 @@ items: parent: minecraft:block/custom/palm_fence_gate behavior: type: block_item - block: - behaviors: - type: fence_gate_block - can-open-with-hand: true - can-open-by-wind-charge: true - sounds: - open: minecraft:block.fence_gate.open - close: minecraft:block.fence_gate.close - loot: - template: default:loot_table/self - settings: - template: - - default:sound/wood - - default:hardness/planks - overrides: - map-color: 2 - instrument: bass - burnable: true - tags: - - minecraft:fence_gates - - minecraft:mineable/axe - - minecraft:unstable_bottom_center - states: - template: default:block_state/fence_gate - arguments: - base_block: oak_fence_gate - model_fence_gate_path: minecraft:block/custom/palm_fence_gate - model_fence_gate_generation: - parent: minecraft:block/template_fence_gate - textures: &textures - texture: minecraft:block/custom/palm_planks - model_fence_gate_open_path: minecraft:block/custom/palm_fence_gate_open - model_fence_gate_open_generation: - parent: minecraft:block/template_fence_gate_open - textures: *textures - model_fence_gate_wall_path: minecraft:block/custom/palm_fence_gate_wall - model_fence_gate_wall_generation: - parent: minecraft:block/template_fence_gate_wall - textures: *textures - model_fence_gate_wall_open_path: minecraft:block/custom/palm_fence_gate_wall_open - model_fence_gate_wall_open_generation: - parent: minecraft:block/template_fence_gate_wall_open - textures: *textures + block: default:palm_fence_gate default:palm_slab: material: nether_brick custom-model-data: 1009 @@ -482,39 +187,7 @@ items: parent: minecraft:block/custom/palm_slab behavior: type: block_item - block: - behaviors: - type: slab_block - loot: - template: default:loot_table/slab - settings: - template: - - default:sound/wood - - default:burn_data/planks - - default:hardness/planks - overrides: - map-color: 2 - instrument: bass - tags: - - minecraft:wooden_slabs - - minecraft:slabs - - minecraft:mineable/axe - states: - template: default:block_state/slab - arguments: - base_block: petrified_oak_slab - model_bottom_path: minecraft:block/custom/palm_slab - model_bottom_generation: - parent: minecraft:block/slab - textures: &textures - bottom: minecraft:block/custom/palm_planks - side: minecraft:block/custom/palm_planks - top: minecraft:block/custom/palm_planks - model_top_path: minecraft:block/custom/palm_slab_top - model_top_generation: - parent: minecraft:block/slab_top - textures: *textures - model_double_path: minecraft:block/custom/palm_planks + block: default:palm_slab default:palm_stairs: material: nether_brick custom-model-data: 1013 @@ -529,42 +202,7 @@ items: fuel-time: 300 behavior: type: block_item - block: - loot: - template: default:loot_table/self - settings: - template: - - default:sound/wood - - default:hardness/planks - - default:burn_data/planks - overrides: - map-color: 2 - instrument: bass - tags: - - minecraft:mineable/axe - - minecraft:stairs - - minecraft:wooden_stairs - behavior: - type: stairs_block - states: - template: default:block_state/stairs - arguments: - base_block: cut_copper_stairs - model_stairs_inner_path: minecraft:block/custom/palm_stairs_inner - model_stairs_inner_generation: - parent: minecraft:block/inner_stairs - textures: &textures - bottom: &block_texture minecraft:block/custom/palm_planks - side: *block_texture - top: *block_texture - model_stairs_outer_path: minecraft:block/custom/palm_stairs_outer - model_stairs_outer_generation: - parent: minecraft:block/outer_stairs - textures: *textures - model_stairs_path: minecraft:block/custom/palm_stairs - model_stairs_generation: - parent: minecraft:block/stairs - textures: *textures + block: default:palm_stairs default:palm_pressure_plate: material: nether_brick custom-model-data: 1014 @@ -579,47 +217,737 @@ items: fuel-time: 300 behavior: type: block_item - block: - loot: - template: default:loot_table/self - settings: - template: - - default:sound/wood - - default:hardness/planks - overrides: - burnable: true - push-reaction: destroy - map-color: 2 - instrument: bass - tags: - - minecraft:mineable/axe - - minecraft:wall_post_override - - minecraft:wooden_pressure_plates - - minecraft:pressure_plates - behaviors: - type: pressure_plate_block - sensitivity: all - pressed-time: 20 - sounds: - on: minecraft:block.wooden_pressure_plate.click_on - off: minecraft:block.wooden_pressure_plate.click_off - states: - template: default:block_state/pressure_plate - arguments: - normal_state: light_weighted_pressure_plate:0 - powered_state: light_weighted_pressure_plate:1 - normal_id: 0 - powered_id: 1 - model_normal_path: minecraft:block/custom/palm_pressure_plate - model_normal_generation: - parent: minecraft:block/pressure_plate_up + block: default:palm_pressure_plate + default:palm_button: + material: nether_brick + custom-model-data: 1015 + model: + type: minecraft:model + path: minecraft:item/custom/palm_button + generation: + parent: minecraft:block/button_inventory + textures: + texture: minecraft:block/custom/palm_planks + data: + item-name: + settings: + fuel-time: 100 + behavior: + type: block_item + block: default:palm_button + default:palm_button_pressed: + material: nether_brick + custom-model-data: 1016 + model: + type: minecraft:model + path: minecraft:block/custom/palm_button_pressed + generation: + parent: minecraft:block/button_pressed + textures: + texture: minecraft:block/custom/palm_planks + default:palm_button_not_pressed: + material: nether_brick + custom-model-data: 1017 + model: + type: minecraft:model + path: minecraft:block/custom/palm_button_not_pressed + generation: + parent: minecraft:block/button + textures: + texture: minecraft:block/custom/palm_planks + +blocks: + default:palm_log: + behavior: + type: strippable_block + stripped: default:stripped_palm_log + loot: + template: default:loot_table/self + settings: + template: default:settings/wood + states: + template: default:block_state/pillar + arguments: + base_block: note_block + texture_top_path: minecraft:block/custom/palm_log_top + texture_side_path: minecraft:block/custom/palm_log + model_vertical_path: minecraft:block/custom/palm_log + model_horizontal_path: minecraft:block/custom/palm_log_horizontal + vanilla_id: + type: self_increase_int + from: 0 + to: 2 + internal_id: + type: self_increase_int + from: 0 + to: 2 + default:stripped_palm_log: + loot: + template: default:loot_table/self + settings: + template: default:settings/wood + states: + template: default:block_state/pillar + arguments: + base_block: note_block + texture_top_path: minecraft:block/custom/stripped_palm_log_top + texture_side_path: minecraft:block/custom/stripped_palm_log + model_vertical_path: minecraft:block/custom/stripped_palm_log + model_horizontal_path: minecraft:block/custom/stripped_palm_log_horizontal + vanilla_id: + type: self_increase_int + from: 3 + to: 5 + internal_id: + type: self_increase_int + from: 3 + to: 5 + default:palm_wood: + behavior: + type: strippable_block + stripped: default:stripped_palm_wood + loot: + template: default:loot_table/self + settings: + template: default:settings/wood + states: + template: default:block_state/pillar + arguments: + base_block: note_block + texture_top_path: minecraft:block/custom/palm_log + texture_side_path: minecraft:block/custom/palm_log + model_vertical_path: minecraft:block/custom/palm_wood + model_horizontal_path: minecraft:block/custom/palm_wood_horizontal + vanilla_id: + type: self_increase_int + from: 6 + to: 8 + internal_id: + type: self_increase_int + from: 6 + to: 8 + default:stripped_palm_wood: + loot: + template: default:loot_table/self + settings: + template: default:settings/wood + states: + template: default:block_state/pillar + arguments: + base_block: note_block + texture_top_path: minecraft:block/custom/stripped_palm_log + texture_side_path: minecraft:block/custom/stripped_palm_log + model_vertical_path: minecraft:block/custom/stripped_palm_wood + model_horizontal_path: minecraft:block/custom/stripped_palm_wood_horizontal + vanilla_id: + type: self_increase_int + from: 9 + to: 11 + internal_id: + type: self_increase_int + from: 9 + to: 11 + default:palm_planks: + settings: + template: default:settings/planks + loot: + template: default:loot_table/self + state: + model: + template: default:model/simplified_cube_all + arguments: + path: minecraft:block/custom/palm_planks + id: 12 + state: note_block:12 + default:palm_sapling: + settings: + template: default:settings/sapling + behaviors: + - type: bush_block + bottom-block-tags: + - minecraft:dirt + - minecraft:farmland + - minecraft:sand + - type: sapling_block + feature: minecraft:fancy_oak + bone-meal-success-chance: 0.45 + loot: + template: default:loot_table/self + states: + properties: + stage: + type: int + default-value: 0 + range: 0~1 + appearances: + default: + state: oak_sapling:0 + model: + path: minecraft:block/custom/palm_sapling + generation: + parent: minecraft:block/cross textures: - texture: minecraft:block/custom/palm_planks - model_powered_path: minecraft:block/custom/palm_pressure_plate_down - model_powered_generation: - parent: minecraft:block/pressure_plate_down - textures: - texture: minecraft:block/custom/palm_planks + cross: minecraft:block/custom/palm_sapling + variants: + stage=0: + appearance: default + id: 0 + stage=1: + appearance: default + id: 1 + default:palm_leaves: + behavior: + type: leaves_block + loot: + template: default:loot_table/leaves + arguments: + leaves: default:palm_leaves + sapling: default:palm_sapling + settings: + template: default:settings/leaves + states: + template: default:block_state/leaves + arguments: + default_state: oak_leaves[distance=1,persistent=false,waterlogged=false] + waterlogged_state: oak_leaves[distance=1,persistent=false,waterlogged=true] + model_path: minecraft:block/custom/palm_leaves + texture_path: minecraft:block/custom/palm_leaves + internal_id: + type: self_increase_int + from: 0 + to: 27 + default:palm_trapdoor: + behavior: + type: trapdoor_block + can-open-with-hand: true + can-open-by-wind-charge: true + sounds: + open: minecraft:block.wooden_trapdoor.open + close: minecraft:block.wooden_trapdoor.close + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + overrides: + map-color: 2 + instrument: bass + hardness: 3.0 + resistance: 3.0 + burnable: true + tags: + - minecraft:mineable/axe + - minecraft:trapdoors + states: + template: default:block_state/trapdoor + arguments: + base_block: acacia_trapdoor + model_bottom_path: minecraft:block/custom/palm_trapdoor_bottom + model_bottom_generation: + parent: minecraft:block/template_orientable_trapdoor_bottom + textures: + texture: minecraft:block/custom/palm_trapdoor + model_open_path: minecraft:block/custom/palm_trapdoor_open + model_open_generation: + parent: minecraft:block/template_orientable_trapdoor_open + textures: + texture: minecraft:block/custom/palm_trapdoor + model_top_path: minecraft:block/custom/palm_trapdoor_top + model_top_generation: + parent: minecraft:block/template_orientable_trapdoor_top + textures: + texture: minecraft:block/custom/palm_trapdoor + default:palm_door: + behavior: + type: door_block + can-open-with-hand: true + can-open-by-wind-charge: true + sounds: + open: minecraft:block.wooden_door.open + close: minecraft:block.wooden_door.close + loot: + template: default:loot_table/door + settings: + template: + - default:sound/wood + overrides: + push-reaction: destroy + map-color: 2 + instrument: bass + hardness: 3.0 + resistance: 3.0 + burnable: true + tags: + - minecraft:wooden_doors + - minecraft:doors + - minecraft:mineable/axe + states: + template: default:block_state/door + arguments: + base_block: oak_door + model_top_left_path: minecraft:block/custom/palm_door_top_left + model_top_left_generation: + parent: minecraft:block/door_top_left + textures: &textures + bottom: minecraft:block/custom/palm_door_bottom + top: minecraft:block/custom/palm_door_top + model_top_right_path: minecraft:block/custom/palm_door_top_right + model_top_right_generation: + parent: minecraft:block/door_top_right + textures: *textures + model_top_left_open_path: minecraft:block/custom/palm_door_top_left_open + model_top_left_open_generation: + parent: minecraft:block/door_top_left_open + textures: *textures + model_top_right_open_path: minecraft:block/custom/palm_door_top_right_open + model_top_right_open_generation: + parent: minecraft:block/door_top_right_open + textures: *textures + model_bottom_left_path: minecraft:block/custom/palm_door_bottom_left + model_bottom_left_generation: + parent: minecraft:block/door_bottom_left + textures: *textures + model_bottom_right_path: minecraft:block/custom/palm_door_bottom_right + model_bottom_right_generation: + parent: minecraft:block/door_bottom_right + textures: *textures + model_bottom_left_open_path: minecraft:block/custom/palm_door_bottom_left_open + model_bottom_left_open_generation: + parent: minecraft:block/door_bottom_left_open + textures: *textures + model_bottom_right_open_path: minecraft:block/custom/palm_door_bottom_right_open + model_bottom_right_open_generation: + parent: minecraft:block/door_bottom_right_open + textures: *textures + default:palm_fence_gate: + behaviors: + type: fence_gate_block + can-open-with-hand: true + can-open-by-wind-charge: true + sounds: + open: minecraft:block.fence_gate.open + close: minecraft:block.fence_gate.close + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + - default:hardness/planks + overrides: + map-color: 2 + instrument: bass + burnable: true + tags: + - minecraft:fence_gates + - minecraft:mineable/axe + - minecraft:unstable_bottom_center + states: + template: default:block_state/fence_gate + arguments: + base_block: oak_fence_gate + model_fence_gate_path: minecraft:block/custom/palm_fence_gate + model_fence_gate_generation: + parent: minecraft:block/template_fence_gate + textures: &textures + texture: minecraft:block/custom/palm_planks + model_fence_gate_open_path: minecraft:block/custom/palm_fence_gate_open + model_fence_gate_open_generation: + parent: minecraft:block/template_fence_gate_open + textures: *textures + model_fence_gate_wall_path: minecraft:block/custom/palm_fence_gate_wall + model_fence_gate_wall_generation: + parent: minecraft:block/template_fence_gate_wall + textures: *textures + model_fence_gate_wall_open_path: minecraft:block/custom/palm_fence_gate_wall_open + model_fence_gate_wall_open_generation: + parent: minecraft:block/template_fence_gate_wall_open + textures: *textures + default:palm_slab: + behaviors: + type: slab_block + loot: + template: default:loot_table/slab + settings: + template: + - default:sound/wood + - default:burn_data/planks + - default:hardness/planks + overrides: + map-color: 2 + instrument: bass + tags: + - minecraft:wooden_slabs + - minecraft:slabs + - minecraft:mineable/axe + states: + template: default:block_state/slab + arguments: + base_block: petrified_oak_slab + model_bottom_path: minecraft:block/custom/palm_slab + model_bottom_generation: + parent: minecraft:block/slab + textures: &textures + bottom: minecraft:block/custom/palm_planks + side: minecraft:block/custom/palm_planks + top: minecraft:block/custom/palm_planks + model_top_path: minecraft:block/custom/palm_slab_top + model_top_generation: + parent: minecraft:block/slab_top + textures: *textures + model_double_path: minecraft:block/custom/palm_planks + default:palm_stairs: + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + - default:hardness/planks + - default:burn_data/planks + overrides: + map-color: 2 + instrument: bass + tags: + - minecraft:mineable/axe + - minecraft:stairs + - minecraft:wooden_stairs + behavior: + type: stairs_block + states: + template: default:block_state/stairs + arguments: + base_block: cut_copper_stairs + model_stairs_inner_path: minecraft:block/custom/palm_stairs_inner + model_stairs_inner_generation: + parent: minecraft:block/inner_stairs + textures: &textures + bottom: &block_texture minecraft:block/custom/palm_planks + side: *block_texture + top: *block_texture + model_stairs_outer_path: minecraft:block/custom/palm_stairs_outer + model_stairs_outer_generation: + parent: minecraft:block/outer_stairs + textures: *textures + model_stairs_path: minecraft:block/custom/palm_stairs + model_stairs_generation: + parent: minecraft:block/stairs + textures: *textures + default:palm_pressure_plate: + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + - default:hardness/planks + overrides: + burnable: true + push-reaction: destroy + map-color: 2 + instrument: bass + tags: + - minecraft:mineable/axe + - minecraft:wall_post_override + - minecraft:wooden_pressure_plates + - minecraft:pressure_plates + behaviors: + type: pressure_plate_block + sensitivity: all + pressed-time: 20 + sounds: + on: minecraft:block.wooden_pressure_plate.click_on + off: minecraft:block.wooden_pressure_plate.click_off + states: + template: default:block_state/pressure_plate + arguments: + normal_state: light_weighted_pressure_plate:0 + powered_state: light_weighted_pressure_plate:1 + normal_id: 0 + powered_id: 1 + model_normal_path: minecraft:block/custom/palm_pressure_plate + model_normal_generation: + parent: minecraft:block/pressure_plate_up + textures: + texture: minecraft:block/custom/palm_planks + model_powered_path: minecraft:block/custom/palm_pressure_plate_down + model_powered_generation: + parent: minecraft:block/pressure_plate_down + textures: + texture: minecraft:block/custom/palm_planks + default:palm_button: + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + - default:hardness/button + overrides: + burnable: true + push-reaction: destroy + map-color: 2 + instrument: harp + tags: + - minecraft:buttons + - minecraft:mineable/axe + - minecraft:wooden_buttons + behaviors: + - type: face_attached_horizontal_directional_block + - type: button_block + ticks-to-stay-pressed: 30 + can-button-be-activated-by-arrows: true + sounds: + on: minecraft:block.wooden_button.click_on + off: minecraft:block.wooden_button.click_off + states: + properties: + powered: + type: boolean + default: false + face: + type: anchor_type + default: floor + facing: + type: 4-direction + default: north + appearances: + face=floor,facing=east,powered=true: + state: birch_button[face=floor,facing=east,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: 0,90,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=west,powered=true: + state: birch_button[face=floor,facing=west,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: 0,-90,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=east,powered=false: + state: birch_button[face=floor,facing=east,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: 0,90,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=west,powered=false: + state: birch_button[face=floor,facing=west,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: 0,-90,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=south,powered=true: + state: birch_button[face=floor,facing=south,powered=true] + entity-renderer: + item: default:palm_button_pressed + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=north,powered=true: + state: birch_button[face=floor,facing=north,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: 0,180,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=south,powered=false: + state: birch_button[face=floor,facing=south,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=north,powered=false: + state: birch_button[face=floor,facing=north,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: 0,180,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=wall,facing=north,powered=true: + state: birch_button[face=wall,facing=north,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: -90,0,0 + scale: 1.0001 + translation: 0,0,-0.0001 + face=wall,facing=south,powered=true: + state: birch_button[face=wall,facing=south,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: 90,0,180 + scale: 1.0001 + translation: 0,0,0.0001 + face=wall,facing=north,powered=false: + state: birch_button[face=wall,facing=north,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: -90,0,0 + scale: 1.0001 + translation: 0,0,-0.0001 + face=wall,facing=south,powered=false: + state: birch_button[face=wall,facing=south,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: 90,0,180 + scale: 1.0001 + translation: 0,0,0.0001 + face=wall,facing=west,powered=true: + state: birch_button[face=wall,facing=west,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: 0,90,90 + scale: 1.0001 + translation: -0.0001,0,0 + face=wall,facing=east,powered=true: + state: birch_button[face=wall,facing=east,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: 0,270,-90 + scale: 1.0001 + translation: 0.0001,0,0 + face=wall,facing=west,powered=false: + state: birch_button[face=wall,facing=west,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: 0,90,90 + scale: 1.0001 + translation: -0.0001,0,0 + face=wall,facing=east,powered=false: + state: birch_button[face=wall,facing=east,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: 0,270,-90 + scale: 1.0001 + translation: 0.0001,0,0 + face=ceiling,facing=north,powered=true: + state: birch_button[face=ceiling,facing=north,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: 0,180,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=south,powered=true: + state: birch_button[face=ceiling,facing=south,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: 0,0,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=north,powered=false: + state: birch_button[face=ceiling,facing=north,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: 0,180,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=south,powered=false: + state: birch_button[face=ceiling,facing=south,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: 0,0,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=west,powered=true: + state: birch_button[face=ceiling,facing=west,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: 0,90,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=east,powered=true: + state: birch_button[face=ceiling,facing=east,powered=true] + entity-renderer: + item: default:palm_button_pressed + rotation: -90,-90,-90 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=west,powered=false: + state: birch_button[face=ceiling,facing=west,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: 0,90,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=east,powered=false: + state: birch_button[face=ceiling,facing=east,powered=false] + entity-renderer: + item: default:palm_button_not_pressed + rotation: -90,-90,-90 + scale: 1.0001 + translation: 0,-0.0001,0 + variants: + face=floor,facing=east,powered=true: + appearance: face=floor,facing=east,powered=true + id: 0 + face=floor,facing=west,powered=true: + appearance: face=floor,facing=west,powered=true + id: 1 + face=floor,facing=east,powered=false: + appearance: face=floor,facing=east,powered=false + id: 2 + face=floor,facing=west,powered=false: + appearance: face=floor,facing=west,powered=false + id: 3 + face=floor,facing=south,powered=true: + appearance: face=floor,facing=south,powered=true + id: 4 + face=floor,facing=north,powered=true: + appearance: face=floor,facing=north,powered=true + id: 5 + face=floor,facing=south,powered=false: + appearance: face=floor,facing=south,powered=false + id: 6 + face=floor,facing=north,powered=false: + appearance: face=floor,facing=north,powered=false + id: 7 + face=wall,facing=north,powered=true: + appearance: face=wall,facing=north,powered=true + id: 8 + face=wall,facing=south,powered=true: + appearance: face=wall,facing=south,powered=true + id: 9 + face=wall,facing=north,powered=false: + appearance: face=wall,facing=north,powered=false + id: 10 + face=wall,facing=south,powered=false: + appearance: face=wall,facing=south,powered=false + id: 11 + face=wall,facing=west,powered=true: + appearance: face=wall,facing=west,powered=true + id: 12 + face=wall,facing=east,powered=true: + appearance: face=wall,facing=east,powered=true + id: 13 + face=wall,facing=west,powered=false: + appearance: face=wall,facing=west,powered=false + id: 14 + face=wall,facing=east,powered=false: + appearance: face=wall,facing=east,powered=false + id: 15 + face=ceiling,facing=north,powered=true: + appearance: face=ceiling,facing=north,powered=true + id: 16 + face=ceiling,facing=south,powered=true: + appearance: face=ceiling,facing=south,powered=true + id: 17 + face=ceiling,facing=north,powered=false: + appearance: face=ceiling,facing=north,powered=false + id: 18 + face=ceiling,facing=south,powered=false: + appearance: face=ceiling,facing=south,powered=false + id: 19 + face=ceiling,facing=west,powered=true: + appearance: face=ceiling,facing=west,powered=true + id: 20 + face=ceiling,facing=east,powered=true: + appearance: face=ceiling,facing=east,powered=true + id: 21 + face=ceiling,facing=west,powered=false: + appearance: face=ceiling,facing=west,powered=false + id: 22 + face=ceiling,facing=east,powered=false: + appearance: face=ceiling,facing=east,powered=false + id: 23 + recipes: default:palm_planks: template: default:recipe/planks @@ -687,11 +1015,18 @@ recipes: default:palm_stairs: type: shaped pattern: - - 'A ' - - 'AA ' - - 'AAA' + - "A " + - "AA " + - "AAA" ingredients: A: default:palm_planks result: id: default:palm_stairs count: 4 + default:palm_button: + type: shapeless + ingredients: + - default:palm_planks + result: + id: default:palm_button + count: 1 diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 7719dacfe..56580ba5c 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -27,6 +27,7 @@ categories: - default:palm_slab - default:palm_stairs - default:palm_pressure_plate + - default:palm_button default:topaz: name: <#FF8C00> hidden: true diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index df4fa5f14..c6d5d3482 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -52,6 +52,7 @@ i18n: item.hami_melon_slice: Hami Melon Slice item.hami_melon: Hami Melon item.hami_melon_seeds: Hami Melon Seeds + item.palm_button: Palm Button category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -113,6 +114,7 @@ i18n: item.hami_melon_slice: 哈密瓜片 item.hami_melon: 哈密瓜 item.hami_melon_seeds: 哈密瓜种子 + item.palm_button: 棕榈木按钮 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 @@ -158,6 +160,7 @@ lang: block_name:default:hami_melon: Hami Melon block_name:default:hami_melon_stem: Hami Melon Stem block_name:default:default:attached_hami_melon_stem: Hami Melon Stem + block_name:default:palm_button: Palm Button zh_cn: block_name:default:chinese_lantern: 灯笼 block_name:default:netherite_anvil: 下界合金砧 @@ -190,4 +193,5 @@ lang: block_name:default:amethyst_wall_torch: 紫水晶火把 block_name:default:hami_melon: 哈密瓜 block_name:default:hami_melon_stem: 哈密瓜茎 - block_name:default:default:attached_hami_melon_stem: 哈密瓜茎 \ No newline at end of file + block_name:default:default:attached_hami_melon_stem: 哈密瓜茎 + block_name:default:palm_button: 棕榈木按钮 From 383d296ce4f541541cde845a5e02218a8d982f10 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 06:44:00 +0800 Subject: [PATCH 048/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=8C=89=E9=92=AE?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/resources/default/configuration/templates.yml | 3 +++ 1 file changed, 3 insertions(+) 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 8e2458b32..6b7a0464b 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -693,6 +693,9 @@ templates#settings#hardness: default:hardness/planks: hardness: 2.0 resistance: 3.0 + default:hardness/button: + hardness: 0.5 + resistance: 0.5 # break level templates#settings#break_level: From 7d90c9bb95128dd5a052ab5fb9d2fc9d8ca1fccf Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 06:54:13 +0800 Subject: [PATCH 049/125] =?UTF-8?q?=E6=8F=90=E5=8F=96=E5=88=B0=E6=A8=A1?= =?UTF-8?q?=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/blocks/palm_tree.yml | 259 +----------------- .../default/configuration/templates.yml | 251 +++++++++++++++++ 2 files changed, 260 insertions(+), 250 deletions(-) diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 7e935d5d5..5f8971688 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -697,256 +697,15 @@ blocks: on: minecraft:block.wooden_button.click_on off: minecraft:block.wooden_button.click_off states: - properties: - powered: - type: boolean - default: false - face: - type: anchor_type - default: floor - facing: - type: 4-direction - default: north - appearances: - face=floor,facing=east,powered=true: - state: birch_button[face=floor,facing=east,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: 0,90,0 - scale: 1.0001 - translation: 0,0.0001,0 - face=floor,facing=west,powered=true: - state: birch_button[face=floor,facing=west,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: 0,-90,0 - scale: 1.0001 - translation: 0,0.0001,0 - face=floor,facing=east,powered=false: - state: birch_button[face=floor,facing=east,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: 0,90,0 - scale: 1.0001 - translation: 0,0.0001,0 - face=floor,facing=west,powered=false: - state: birch_button[face=floor,facing=west,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: 0,-90,0 - scale: 1.0001 - translation: 0,0.0001,0 - face=floor,facing=south,powered=true: - state: birch_button[face=floor,facing=south,powered=true] - entity-renderer: - item: default:palm_button_pressed - scale: 1.0001 - translation: 0,0.0001,0 - face=floor,facing=north,powered=true: - state: birch_button[face=floor,facing=north,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: 0,180,0 - scale: 1.0001 - translation: 0,0.0001,0 - face=floor,facing=south,powered=false: - state: birch_button[face=floor,facing=south,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - scale: 1.0001 - translation: 0,0.0001,0 - face=floor,facing=north,powered=false: - state: birch_button[face=floor,facing=north,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: 0,180,0 - scale: 1.0001 - translation: 0,0.0001,0 - face=wall,facing=north,powered=true: - state: birch_button[face=wall,facing=north,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: -90,0,0 - scale: 1.0001 - translation: 0,0,-0.0001 - face=wall,facing=south,powered=true: - state: birch_button[face=wall,facing=south,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: 90,0,180 - scale: 1.0001 - translation: 0,0,0.0001 - face=wall,facing=north,powered=false: - state: birch_button[face=wall,facing=north,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: -90,0,0 - scale: 1.0001 - translation: 0,0,-0.0001 - face=wall,facing=south,powered=false: - state: birch_button[face=wall,facing=south,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: 90,0,180 - scale: 1.0001 - translation: 0,0,0.0001 - face=wall,facing=west,powered=true: - state: birch_button[face=wall,facing=west,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: 0,90,90 - scale: 1.0001 - translation: -0.0001,0,0 - face=wall,facing=east,powered=true: - state: birch_button[face=wall,facing=east,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: 0,270,-90 - scale: 1.0001 - translation: 0.0001,0,0 - face=wall,facing=west,powered=false: - state: birch_button[face=wall,facing=west,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: 0,90,90 - scale: 1.0001 - translation: -0.0001,0,0 - face=wall,facing=east,powered=false: - state: birch_button[face=wall,facing=east,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: 0,270,-90 - scale: 1.0001 - translation: 0.0001,0,0 - face=ceiling,facing=north,powered=true: - state: birch_button[face=ceiling,facing=north,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: 0,180,180 - scale: 1.0001 - translation: 0,-0.0001,0 - face=ceiling,facing=south,powered=true: - state: birch_button[face=ceiling,facing=south,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: 0,0,180 - scale: 1.0001 - translation: 0,-0.0001,0 - face=ceiling,facing=north,powered=false: - state: birch_button[face=ceiling,facing=north,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: 0,180,180 - scale: 1.0001 - translation: 0,-0.0001,0 - face=ceiling,facing=south,powered=false: - state: birch_button[face=ceiling,facing=south,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: 0,0,180 - scale: 1.0001 - translation: 0,-0.0001,0 - face=ceiling,facing=west,powered=true: - state: birch_button[face=ceiling,facing=west,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: 0,90,180 - scale: 1.0001 - translation: 0,-0.0001,0 - face=ceiling,facing=east,powered=true: - state: birch_button[face=ceiling,facing=east,powered=true] - entity-renderer: - item: default:palm_button_pressed - rotation: -90,-90,-90 - scale: 1.0001 - translation: 0,-0.0001,0 - face=ceiling,facing=west,powered=false: - state: birch_button[face=ceiling,facing=west,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: 0,90,180 - scale: 1.0001 - translation: 0,-0.0001,0 - face=ceiling,facing=east,powered=false: - state: birch_button[face=ceiling,facing=east,powered=false] - entity-renderer: - item: default:palm_button_not_pressed - rotation: -90,-90,-90 - scale: 1.0001 - translation: 0,-0.0001,0 - variants: - face=floor,facing=east,powered=true: - appearance: face=floor,facing=east,powered=true - id: 0 - face=floor,facing=west,powered=true: - appearance: face=floor,facing=west,powered=true - id: 1 - face=floor,facing=east,powered=false: - appearance: face=floor,facing=east,powered=false - id: 2 - face=floor,facing=west,powered=false: - appearance: face=floor,facing=west,powered=false - id: 3 - face=floor,facing=south,powered=true: - appearance: face=floor,facing=south,powered=true - id: 4 - face=floor,facing=north,powered=true: - appearance: face=floor,facing=north,powered=true - id: 5 - face=floor,facing=south,powered=false: - appearance: face=floor,facing=south,powered=false - id: 6 - face=floor,facing=north,powered=false: - appearance: face=floor,facing=north,powered=false - id: 7 - face=wall,facing=north,powered=true: - appearance: face=wall,facing=north,powered=true - id: 8 - face=wall,facing=south,powered=true: - appearance: face=wall,facing=south,powered=true - id: 9 - face=wall,facing=north,powered=false: - appearance: face=wall,facing=north,powered=false - id: 10 - face=wall,facing=south,powered=false: - appearance: face=wall,facing=south,powered=false - id: 11 - face=wall,facing=west,powered=true: - appearance: face=wall,facing=west,powered=true - id: 12 - face=wall,facing=east,powered=true: - appearance: face=wall,facing=east,powered=true - id: 13 - face=wall,facing=west,powered=false: - appearance: face=wall,facing=west,powered=false - id: 14 - face=wall,facing=east,powered=false: - appearance: face=wall,facing=east,powered=false - id: 15 - face=ceiling,facing=north,powered=true: - appearance: face=ceiling,facing=north,powered=true - id: 16 - face=ceiling,facing=south,powered=true: - appearance: face=ceiling,facing=south,powered=true - id: 17 - face=ceiling,facing=north,powered=false: - appearance: face=ceiling,facing=north,powered=false - id: 18 - face=ceiling,facing=south,powered=false: - appearance: face=ceiling,facing=south,powered=false - id: 19 - face=ceiling,facing=west,powered=true: - appearance: face=ceiling,facing=west,powered=true - id: 20 - face=ceiling,facing=east,powered=true: - appearance: face=ceiling,facing=east,powered=true - id: 21 - face=ceiling,facing=west,powered=false: - appearance: face=ceiling,facing=west,powered=false - id: 22 - face=ceiling,facing=east,powered=false: - appearance: face=ceiling,facing=east,powered=false - id: 23 + template: default:block_state/button + arguments: + base_block: birch_button + pressed_item: default:palm_button_pressed + not_pressed_item: default:palm_button_not_pressed + internal_id: + type: self_increase_int + from: 0 + to: 23 recipes: default:palm_planks: 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 6b7a0464b..b204df7ba 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -3138,6 +3138,257 @@ templates#block_states: powered=true: appearance: powered id: ${powered_id} + default:block_state/button: + properties: + powered: + type: boolean + default: false + face: + type: anchor_type + default: floor + facing: + type: 4-direction + default: north + appearances: + face=floor,facing=east,powered=true: + state: ${base_block}[face=floor,facing=east,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: 0,90,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=west,powered=true: + state: ${base_block}[face=floor,facing=west,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: 0,-90,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=east,powered=false: + state: ${base_block}[face=floor,facing=east,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: 0,90,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=west,powered=false: + state: ${base_block}[face=floor,facing=west,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: 0,-90,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=south,powered=true: + state: ${base_block}[face=floor,facing=south,powered=true] + entity-renderer: + item: ${pressed_item} + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=north,powered=true: + state: ${base_block}[face=floor,facing=north,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: 0,180,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=south,powered=false: + state: ${base_block}[face=floor,facing=south,powered=false] + entity-renderer: + item: ${not_pressed_item} + scale: 1.0001 + translation: 0,0.0001,0 + face=floor,facing=north,powered=false: + state: ${base_block}[face=floor,facing=north,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: 0,180,0 + scale: 1.0001 + translation: 0,0.0001,0 + face=wall,facing=north,powered=true: + state: ${base_block}[face=wall,facing=north,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: -90,0,0 + scale: 1.0001 + translation: 0,0,-0.0001 + face=wall,facing=south,powered=true: + state: ${base_block}[face=wall,facing=south,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: 90,0,180 + scale: 1.0001 + translation: 0,0,0.0001 + face=wall,facing=north,powered=false: + state: ${base_block}[face=wall,facing=north,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: -90,0,0 + scale: 1.0001 + translation: 0,0,-0.0001 + face=wall,facing=south,powered=false: + state: ${base_block}[face=wall,facing=south,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: 90,0,180 + scale: 1.0001 + translation: 0,0,0.0001 + face=wall,facing=west,powered=true: + state: ${base_block}[face=wall,facing=west,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: 0,90,90 + scale: 1.0001 + translation: -0.0001,0,0 + face=wall,facing=east,powered=true: + state: ${base_block}[face=wall,facing=east,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: 0,270,-90 + scale: 1.0001 + translation: 0.0001,0,0 + face=wall,facing=west,powered=false: + state: ${base_block}[face=wall,facing=west,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: 0,90,90 + scale: 1.0001 + translation: -0.0001,0,0 + face=wall,facing=east,powered=false: + state: ${base_block}[face=wall,facing=east,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: 0,270,-90 + scale: 1.0001 + translation: 0.0001,0,0 + face=ceiling,facing=north,powered=true: + state: ${base_block}[face=ceiling,facing=north,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: 0,180,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=south,powered=true: + state: ${base_block}[face=ceiling,facing=south,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: 0,0,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=north,powered=false: + state: ${base_block}[face=ceiling,facing=north,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: 0,180,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=south,powered=false: + state: ${base_block}[face=ceiling,facing=south,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: 0,0,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=west,powered=true: + state: ${base_block}[face=ceiling,facing=west,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: 0,90,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=east,powered=true: + state: ${base_block}[face=ceiling,facing=east,powered=true] + entity-renderer: + item: ${pressed_item} + rotation: -90,-90,-90 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=west,powered=false: + state: ${base_block}[face=ceiling,facing=west,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: 0,90,180 + scale: 1.0001 + translation: 0,-0.0001,0 + face=ceiling,facing=east,powered=false: + state: ${base_block}[face=ceiling,facing=east,powered=false] + entity-renderer: + item: ${not_pressed_item} + rotation: -90,-90,-90 + scale: 1.0001 + translation: 0,-0.0001,0 + variants: + face=floor,facing=east,powered=true: + appearance: face=floor,facing=east,powered=true + id: ${internal_id} + face=floor,facing=west,powered=true: + appearance: face=floor,facing=west,powered=true + id: ${internal_id} + face=floor,facing=east,powered=false: + appearance: face=floor,facing=east,powered=false + id: ${internal_id} + face=floor,facing=west,powered=false: + appearance: face=floor,facing=west,powered=false + id: ${internal_id} + face=floor,facing=south,powered=true: + appearance: face=floor,facing=south,powered=true + id: ${internal_id} + face=floor,facing=north,powered=true: + appearance: face=floor,facing=north,powered=true + id: ${internal_id} + face=floor,facing=south,powered=false: + appearance: face=floor,facing=south,powered=false + id: ${internal_id} + face=floor,facing=north,powered=false: + appearance: face=floor,facing=north,powered=false + id: ${internal_id} + face=wall,facing=north,powered=true: + appearance: face=wall,facing=north,powered=true + id: ${internal_id} + face=wall,facing=south,powered=true: + appearance: face=wall,facing=south,powered=true + id: ${internal_id} + face=wall,facing=north,powered=false: + appearance: face=wall,facing=north,powered=false + id: ${internal_id} + face=wall,facing=south,powered=false: + appearance: face=wall,facing=south,powered=false + id: ${internal_id} + face=wall,facing=west,powered=true: + appearance: face=wall,facing=west,powered=true + id: ${internal_id} + face=wall,facing=east,powered=true: + appearance: face=wall,facing=east,powered=true + id: ${internal_id} + face=wall,facing=west,powered=false: + appearance: face=wall,facing=west,powered=false + id: ${internal_id} + face=wall,facing=east,powered=false: + appearance: face=wall,facing=east,powered=false + id: ${internal_id} + face=ceiling,facing=north,powered=true: + appearance: face=ceiling,facing=north,powered=true + id: ${internal_id} + face=ceiling,facing=south,powered=true: + appearance: face=ceiling,facing=south,powered=true + id: ${internal_id} + face=ceiling,facing=north,powered=false: + appearance: face=ceiling,facing=north,powered=false + id: ${internal_id} + face=ceiling,facing=south,powered=false: + appearance: face=ceiling,facing=south,powered=false + id: ${internal_id} + face=ceiling,facing=west,powered=true: + appearance: face=ceiling,facing=west,powered=true + id: ${internal_id} + face=ceiling,facing=east,powered=true: + appearance: face=ceiling,facing=east,powered=true + id: ${internal_id} + face=ceiling,facing=west,powered=false: + appearance: face=ceiling,facing=west,powered=false + id: ${internal_id} + face=ceiling,facing=east,powered=false: + appearance: face=ceiling,facing=east,powered=false + id: ${internal_id} # recipes templates#recipes: default:recipe/planks: From ff98255791a511380bbef90bf1f9c360484d05e1 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 08:52:39 +0800 Subject: [PATCH 050/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=85=E6=A0=8F?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/blocks/hami_melon.yml | 70 +- .../configuration/blocks/palm_tree.yml | 76 +++ .../default/configuration/categories.yml | 1 + .../resources/default/configuration/i18n.yml | 4 + .../default/configuration/templates.yml | 637 ++++++++++++++++-- .../models/block/custom/fence_side.json | 29 + .../core/pack/AbstractPackManager.java | 1 + 7 files changed, 738 insertions(+), 80 deletions(-) create mode 100644 common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fence_side.json diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml index 3d2cb6e37..356d62b63 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml @@ -69,16 +69,18 @@ blocks: max: 9 - type: explosion_decay settings: - map-color: 19 - hardness: 1 - resistance: 1 - push-reaction: DESTROY - is-suffocating: true - is-redstone-conductor: true - tags: - - minecraft:enderman_holdable - - minecraft:mineable/axe - - minecraft:sword_efficient + template: + - default:sound/wood + - default:hardness/melon + overrides: + map-color: 19 + push-reaction: DESTROY + is-suffocating: true + is-redstone-conductor: true + tags: + - minecraft:enderman_holdable + - minecraft:mineable/axe + - minecraft:sword_efficient state: id: 30 state: note_block:30 @@ -184,18 +186,20 @@ blocks: functions: - type: explosion_decay settings: - map-color: 7 - hardness: 0 - resistance: 0 - push-reaction: DESTROY - is-suffocating: false - is-redstone-conductor: false - item: default:hami_melon_seeds - is-randomly-ticking: true - tags: - - minecraft:bee_growables - - minecraft:crops - - minecraft:maintains_farmland + template: + - default:sound/stem_crop + - default:hardness/none + overrides: + map-color: 7 + push-reaction: DESTROY + is-suffocating: false + is-redstone-conductor: false + item: default:hami_melon_seeds + is-randomly-ticking: true + tags: + - minecraft:bee_growables + - minecraft:crops + - minecraft:maintains_farmland behaviors: - type: stem_block fruit: default:hami_melon @@ -268,16 +272,18 @@ blocks: functions: - type: explosion_decay settings: - map-color: 7 - hardness: 0 - resistance: 0 - push-reaction: DESTROY - is-suffocating: false - is-redstone-conductor: false - item: default:hami_melon_seeds - is-randomly-ticking: true - tags: - - minecraft:maintains_farmland + template: + - default:sound/stem_crop + - default:hardness/none + overrides: + map-color: 7 + push-reaction: DESTROY + is-suffocating: false + is-redstone-conductor: false + item: default:hami_melon_seeds + is-randomly-ticking: true + tags: + - minecraft:maintains_farmland behaviors: - type: attached_stem_block fruit: default:hami_melon diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 5f8971688..47523c47b 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -255,6 +255,38 @@ items: parent: minecraft:block/button textures: texture: minecraft:block/custom/palm_planks + default:palm_fence: + material: nether_brick + data: + item-name: + model: + type: minecraft:model + path: minecraft:item/custom/palm_fence_inventory + generation: + parent: minecraft:block/fence_inventory + textures: + texture: minecraft:block/custom/palm_planks + behavior: + type: block_item + block: default:palm_fence + default:palm_fence_post: + material: nether_brick + model: + type: minecraft:model + path: minecraft:block/custom/palm_fence_post + generation: + parent: minecraft:block/fence_post + textures: + texture: minecraft:block/custom/palm_planks + default:palm_fence_side: + material: nether_brick + model: + type: minecraft:model + path: minecraft:block/custom/palm_fence_side + generation: + parent: minecraft:block/custom/fence_side + textures: + texture: minecraft:block/custom/palm_planks blocks: default:palm_log: @@ -706,6 +738,39 @@ blocks: type: self_increase_int from: 0 to: 23 + default:palm_fence: + settings: + template: + - default:hardness/planks + - default:sound/wood + overrides: + burn-chance: 5 + fire-spread-chance: 20 + burnable: true + is-suffocating: false + is-redstone-conductor: false + push-reaction: NORMAL + instrument: BASS + map-color: 2 + tags: + - minecraft:fences + - minecraft:mineable/axe + - minecraft:wooden_fences + behavior: + type: fence_block + self-tag: fences + connectable-tag: wooden_fences + can-leash: true + states: + template: default:block_state/fence + arguments: + base_block: oak_fence + fence_post_item: default:palm_fence_post + fence_side_item: default:palm_fence_side + internal_id: + type: self_increase_int + from: 0 + to: 31 recipes: default:palm_planks: @@ -789,3 +854,14 @@ recipes: result: id: default:palm_button count: 1 + default:palm_fence: + type: shaped + pattern: + - ABA + - ABA + ingredients: + A: default:palm_planks + B: minecraft:stick + result: + id: default:palm_fence + count: 1 diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 56580ba5c..2d911abe4 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -28,6 +28,7 @@ categories: - default:palm_stairs - default:palm_pressure_plate - default:palm_button + - default:palm_fence default:topaz: name: <#FF8C00> hidden: true diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index c6d5d3482..71d6e9e30 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -53,6 +53,7 @@ i18n: item.hami_melon: Hami Melon item.hami_melon_seeds: Hami Melon Seeds item.palm_button: Palm Button + item.palm_fence: Palm Fence category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -115,6 +116,7 @@ i18n: item.hami_melon: 哈密瓜 item.hami_melon_seeds: 哈密瓜种子 item.palm_button: 棕榈木按钮 + item.palm_fence: 棕榈木栅栏 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 @@ -161,6 +163,7 @@ lang: block_name:default:hami_melon_stem: Hami Melon Stem block_name:default:default:attached_hami_melon_stem: Hami Melon Stem block_name:default:palm_button: Palm Button + block_name:default:palm_fence: Palm Fence zh_cn: block_name:default:chinese_lantern: 灯笼 block_name:default:netherite_anvil: 下界合金砧 @@ -195,3 +198,4 @@ lang: block_name:default:hami_melon_stem: 哈密瓜茎 block_name:default:default:attached_hami_melon_stem: 哈密瓜茎 block_name:default:palm_button: 棕榈木按钮 + block_name:default:palm_fence: 棕榈木栅栏 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 b204df7ba..fa284b068 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -576,6 +576,13 @@ templates#settings#sounds: place: minecraft:item.crop.plant hit: minecraft:block.grass.hit fall: minecraft:block.grass.fall + default:sound/stem_crop: + sounds: + break: minecraft:block.crop.break + step: minecraft:block.wood.step + place: minecraft:item.crop.plant + hit: minecraft:block.wood.hit + fall: minecraft:block.wood.fall default:sound/grass: template: default:sound/block_template arguments: @@ -696,6 +703,9 @@ templates#settings#hardness: default:hardness/button: hardness: 0.5 resistance: 0.5 + default:hardness/melon: + hardness: 1.0 + resistance: 1.0 # break level templates#settings#break_level: @@ -3155,167 +3165,167 @@ templates#block_states: entity-renderer: item: ${pressed_item} rotation: 0,90,0 - scale: 1.0001 - translation: 0,0.0001,0 + scale: 1.0005 + translation: 0,0.00023,0 face=floor,facing=west,powered=true: state: ${base_block}[face=floor,facing=west,powered=true] entity-renderer: item: ${pressed_item} rotation: 0,-90,0 - scale: 1.0001 - translation: 0,0.0001,0 + scale: 1.0005 + translation: 0,0.00023,0 face=floor,facing=east,powered=false: state: ${base_block}[face=floor,facing=east,powered=false] entity-renderer: item: ${not_pressed_item} rotation: 0,90,0 - scale: 1.0001 - translation: 0,0.0001,0 + scale: 1.0005 + translation: 0,0.00023,0 face=floor,facing=west,powered=false: state: ${base_block}[face=floor,facing=west,powered=false] entity-renderer: item: ${not_pressed_item} rotation: 0,-90,0 - scale: 1.0001 - translation: 0,0.0001,0 + scale: 1.0005 + translation: 0,0.00023,0 face=floor,facing=south,powered=true: state: ${base_block}[face=floor,facing=south,powered=true] entity-renderer: item: ${pressed_item} - scale: 1.0001 - translation: 0,0.0001,0 + scale: 1.0005 + translation: 0,0.00023,0 face=floor,facing=north,powered=true: state: ${base_block}[face=floor,facing=north,powered=true] entity-renderer: item: ${pressed_item} rotation: 0,180,0 - scale: 1.0001 - translation: 0,0.0001,0 + scale: 1.0005 + translation: 0,0.00023,0 face=floor,facing=south,powered=false: state: ${base_block}[face=floor,facing=south,powered=false] entity-renderer: item: ${not_pressed_item} - scale: 1.0001 - translation: 0,0.0001,0 + scale: 1.0005 + translation: 0,0.00023,0 face=floor,facing=north,powered=false: state: ${base_block}[face=floor,facing=north,powered=false] entity-renderer: item: ${not_pressed_item} rotation: 0,180,0 - scale: 1.0001 - translation: 0,0.0001,0 + scale: 1.0005 + translation: 0,0.00023,0 face=wall,facing=north,powered=true: state: ${base_block}[face=wall,facing=north,powered=true] entity-renderer: item: ${pressed_item} rotation: -90,0,0 - scale: 1.0001 - translation: 0,0,-0.0001 + scale: 1.0005 + translation: 0,0,-0.00023 face=wall,facing=south,powered=true: state: ${base_block}[face=wall,facing=south,powered=true] entity-renderer: item: ${pressed_item} rotation: 90,0,180 - scale: 1.0001 - translation: 0,0,0.0001 + scale: 1.0005 + translation: 0,0,0.00023 face=wall,facing=north,powered=false: state: ${base_block}[face=wall,facing=north,powered=false] entity-renderer: item: ${not_pressed_item} rotation: -90,0,0 - scale: 1.0001 - translation: 0,0,-0.0001 + scale: 1.0005 + translation: 0,0,-0.00023 face=wall,facing=south,powered=false: state: ${base_block}[face=wall,facing=south,powered=false] entity-renderer: item: ${not_pressed_item} rotation: 90,0,180 - scale: 1.0001 - translation: 0,0,0.0001 + scale: 1.0005 + translation: 0,0,0.00023 face=wall,facing=west,powered=true: state: ${base_block}[face=wall,facing=west,powered=true] entity-renderer: item: ${pressed_item} rotation: 0,90,90 - scale: 1.0001 - translation: -0.0001,0,0 + scale: 1.0005 + translation: -0.00023,0,0 face=wall,facing=east,powered=true: state: ${base_block}[face=wall,facing=east,powered=true] entity-renderer: item: ${pressed_item} rotation: 0,270,-90 - scale: 1.0001 - translation: 0.0001,0,0 + scale: 1.0005 + translation: 0.00023,0,0 face=wall,facing=west,powered=false: state: ${base_block}[face=wall,facing=west,powered=false] entity-renderer: item: ${not_pressed_item} rotation: 0,90,90 - scale: 1.0001 - translation: -0.0001,0,0 + scale: 1.0005 + translation: -0.00023,0,0 face=wall,facing=east,powered=false: state: ${base_block}[face=wall,facing=east,powered=false] entity-renderer: item: ${not_pressed_item} rotation: 0,270,-90 - scale: 1.0001 - translation: 0.0001,0,0 + scale: 1.0005 + translation: 0.00023,0,0 face=ceiling,facing=north,powered=true: state: ${base_block}[face=ceiling,facing=north,powered=true] entity-renderer: item: ${pressed_item} rotation: 0,180,180 - scale: 1.0001 - translation: 0,-0.0001,0 + scale: 1.0005 + translation: 0,-0.00023,0 face=ceiling,facing=south,powered=true: state: ${base_block}[face=ceiling,facing=south,powered=true] entity-renderer: item: ${pressed_item} rotation: 0,0,180 - scale: 1.0001 - translation: 0,-0.0001,0 + scale: 1.0005 + translation: 0,-0.00023,0 face=ceiling,facing=north,powered=false: state: ${base_block}[face=ceiling,facing=north,powered=false] entity-renderer: item: ${not_pressed_item} rotation: 0,180,180 - scale: 1.0001 - translation: 0,-0.0001,0 + scale: 1.0005 + translation: 0,-0.00023,0 face=ceiling,facing=south,powered=false: state: ${base_block}[face=ceiling,facing=south,powered=false] entity-renderer: item: ${not_pressed_item} rotation: 0,0,180 - scale: 1.0001 - translation: 0,-0.0001,0 + scale: 1.0005 + translation: 0,-0.00023,0 face=ceiling,facing=west,powered=true: state: ${base_block}[face=ceiling,facing=west,powered=true] entity-renderer: item: ${pressed_item} rotation: 0,90,180 - scale: 1.0001 - translation: 0,-0.0001,0 + scale: 1.0005 + translation: 0,-0.00023,0 face=ceiling,facing=east,powered=true: state: ${base_block}[face=ceiling,facing=east,powered=true] entity-renderer: item: ${pressed_item} rotation: -90,-90,-90 - scale: 1.0001 - translation: 0,-0.0001,0 + scale: 1.0005 + translation: 0,-0.00023,0 face=ceiling,facing=west,powered=false: state: ${base_block}[face=ceiling,facing=west,powered=false] entity-renderer: item: ${not_pressed_item} rotation: 0,90,180 - scale: 1.0001 - translation: 0,-0.0001,0 + scale: 1.0005 + translation: 0,-0.00023,0 face=ceiling,facing=east,powered=false: state: ${base_block}[face=ceiling,facing=east,powered=false] entity-renderer: item: ${not_pressed_item} rotation: -90,-90,-90 - scale: 1.0001 - translation: 0,-0.0001,0 + scale: 1.0005 + translation: 0,-0.00023,0 variants: face=floor,facing=east,powered=true: appearance: face=floor,facing=east,powered=true @@ -3389,6 +3399,537 @@ templates#block_states: face=ceiling,facing=east,powered=false: appearance: face=ceiling,facing=east,powered=false id: ${internal_id} + default:block_state/fence: + properties: + north: + type: boolean + default: false + east: + type: boolean + default: false + south: + type: boolean + default: false + west: + type: boolean + default: false + waterlogged: + type: boolean + default: false + appearances: + east=false,north=false,south=false,waterlogged=false,west=false: + state: ${base_block}[east=false,north=false,south=false,waterlogged=false,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + east=true,north=false,south=false,waterlogged=false,west=false: + state: ${base_block}[east=true,north=false,south=false,waterlogged=false,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 270 + east=false,north=true,south=false,waterlogged=false,west=false: + state: ${base_block}[east=false,north=true,south=false,waterlogged=false,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 180 + east=false,north=false,south=true,waterlogged=false,west=false: + state: ${base_block}[east=false,north=false,south=true,waterlogged=false,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + east=false,north=false,south=false,waterlogged=false,west=true: + state: ${base_block}[east=false,north=false,south=false,waterlogged=false,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 90 + east=true,north=true,south=false,waterlogged=false,west=false: + state: ${base_block}[east=true,north=true,south=false,waterlogged=false,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 180 + - item: ${fence_side_item} + rotation: 270 + east=true,north=false,south=true,waterlogged=false,west=false: + state: ${base_block}[east=true,north=false,south=true,waterlogged=false,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 270 + east=true,north=false,south=false,waterlogged=false,west=true: + state: ${base_block}[east=true,north=false,south=false,waterlogged=false,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 270 + east=false,north=true,south=true,waterlogged=false,west=false: + state: ${base_block}[east=false,north=true,south=true,waterlogged=false,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 180 + east=false,north=true,south=false,waterlogged=false,west=true: + state: ${base_block}[east=false,north=true,south=false,waterlogged=false,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 180 + east=false,north=false,south=true,waterlogged=false,west=true: + state: ${base_block}[east=false,north=false,south=true,waterlogged=false,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 90 + east=true,north=true,south=true,waterlogged=false,west=false: + state: ${base_block}[east=true,north=true,south=true,waterlogged=false,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 180 + - item: ${fence_side_item} + rotation: 270 + east=true,north=true,south=false,waterlogged=false,west=true: + state: ${base_block}[east=true,north=true,south=false,waterlogged=false,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 180 + - item: ${fence_side_item} + rotation: 270 + east=true,north=false,south=true,waterlogged=false,west=true: + state: ${base_block}[east=true,north=false,south=true,waterlogged=false,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 270 + east=false,north=true,south=true,waterlogged=false,west=true: + state: ${base_block}[east=false,north=true,south=true,waterlogged=false,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 180 + east=true,north=true,south=true,waterlogged=false,west=true: + state: ${base_block}[east=true,north=true,south=true,waterlogged=false,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 180 + - item: ${fence_side_item} + rotation: 270 + east=false,north=false,south=false,waterlogged=true,west=false: + state: ${base_block}[east=false,north=false,south=false,waterlogged=true,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + east=true,north=false,south=false,waterlogged=true,west=false: + state: ${base_block}[east=true,north=false,south=false,waterlogged=true,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 270 + east=false,north=true,south=false,waterlogged=true,west=false: + state: ${base_block}[east=false,north=true,south=false,waterlogged=true,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 180 + east=false,north=false,south=true,waterlogged=true,west=false: + state: ${base_block}[east=false,north=false,south=true,waterlogged=true,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + east=false,north=false,south=false,waterlogged=true,west=true: + state: ${base_block}[east=false,north=false,south=false,waterlogged=true,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 90 + east=true,north=true,south=false,waterlogged=true,west=false: + state: ${base_block}[east=true,north=true,south=false,waterlogged=true,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 180 + - item: ${fence_side_item} + rotation: 270 + east=true,north=false,south=true,waterlogged=true,west=false: + state: ${base_block}[east=true,north=false,south=true,waterlogged=true,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 270 + east=true,north=false,south=false,waterlogged=true,west=true: + state: ${base_block}[east=true,north=false,south=false,waterlogged=true,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 270 + east=false,north=true,south=true,waterlogged=true,west=false: + state: ${base_block}[east=false,north=true,south=true,waterlogged=true,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 180 + east=false,north=true,south=false,waterlogged=true,west=true: + state: ${base_block}[east=false,north=true,south=false,waterlogged=true,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 180 + east=false,north=false,south=true,waterlogged=true,west=true: + state: ${base_block}[east=false,north=false,south=true,waterlogged=true,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 90 + east=true,north=true,south=true,waterlogged=true,west=false: + state: ${base_block}[east=true,north=true,south=true,waterlogged=true,west=false] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 180 + - item: ${fence_side_item} + rotation: 270 + east=true,north=true,south=false,waterlogged=true,west=true: + state: ${base_block}[east=true,north=true,south=false,waterlogged=true,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 180 + - item: ${fence_side_item} + rotation: 270 + east=true,north=false,south=true,waterlogged=true,west=true: + state: ${base_block}[east=true,north=false,south=true,waterlogged=true,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 270 + east=false,north=true,south=true,waterlogged=true,west=true: + state: ${base_block}[east=false,north=true,south=true,waterlogged=true,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 180 + east=true,north=true,south=true,waterlogged=true,west=true: + state: ${base_block}[east=true,north=true,south=true,waterlogged=true,west=true] + entity-renderer: + - item: ${fence_post_item} + rotation: 180 + scale: 1.0003 + translation: 0,0.0001,0 + - item: ${fence_side_item} + rotation: 0 + - item: ${fence_side_item} + rotation: 90 + - item: ${fence_side_item} + rotation: 180 + - item: ${fence_side_item} + rotation: 270 + variants: + east=false,north=false,south=false,waterlogged=false,west=false: + appearance: east=false,north=false,south=false,waterlogged=false,west=false + id: ${internal_id} + east=true,north=false,south=false,waterlogged=false,west=false: + appearance: east=true,north=false,south=false,waterlogged=false,west=false + id: ${internal_id} + east=false,north=true,south=false,waterlogged=false,west=false: + appearance: east=false,north=true,south=false,waterlogged=false,west=false + id: ${internal_id} + east=false,north=false,south=true,waterlogged=false,west=false: + appearance: east=false,north=false,south=true,waterlogged=false,west=false + id: ${internal_id} + east=false,north=false,south=false,waterlogged=false,west=true: + appearance: east=false,north=false,south=false,waterlogged=false,west=true + id: ${internal_id} + east=true,north=true,south=false,waterlogged=false,west=false: + appearance: east=true,north=true,south=false,waterlogged=false,west=false + id: ${internal_id} + east=true,north=false,south=true,waterlogged=false,west=false: + appearance: east=true,north=false,south=true,waterlogged=false,west=false + id: ${internal_id} + east=true,north=false,south=false,waterlogged=false,west=true: + appearance: east=true,north=false,south=false,waterlogged=false,west=true + id: ${internal_id} + east=false,north=true,south=true,waterlogged=false,west=false: + appearance: east=false,north=true,south=true,waterlogged=false,west=false + id: ${internal_id} + east=false,north=true,south=false,waterlogged=false,west=true: + appearance: east=false,north=true,south=false,waterlogged=false,west=true + id: ${internal_id} + east=false,north=false,south=true,waterlogged=false,west=true: + appearance: east=false,north=false,south=true,waterlogged=false,west=true + id: ${internal_id} + east=true,north=true,south=true,waterlogged=false,west=false: + appearance: east=true,north=true,south=true,waterlogged=false,west=false + id: ${internal_id} + east=true,north=true,south=false,waterlogged=false,west=true: + appearance: east=true,north=true,south=false,waterlogged=false,west=true + id: ${internal_id} + east=true,north=false,south=true,waterlogged=false,west=true: + appearance: east=true,north=false,south=true,waterlogged=false,west=true + id: ${internal_id} + east=false,north=true,south=true,waterlogged=false,west=true: + appearance: east=false,north=true,south=true,waterlogged=false,west=true + id: ${internal_id} + east=true,north=true,south=true,waterlogged=false,west=true: + appearance: east=true,north=true,south=true,waterlogged=false,west=true + id: ${internal_id} + east=false,north=false,south=false,waterlogged=true,west=false: + appearance: east=false,north=false,south=false,waterlogged=true,west=false + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=true,north=false,south=false,waterlogged=true,west=false: + appearance: east=true,north=false,south=false,waterlogged=true,west=false + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=false,north=true,south=false,waterlogged=true,west=false: + appearance: east=false,north=true,south=false,waterlogged=true,west=false + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=false,north=false,south=true,waterlogged=true,west=false: + appearance: east=false,north=false,south=true,waterlogged=true,west=false + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=false,north=false,south=false,waterlogged=true,west=true: + appearance: east=false,north=false,south=false,waterlogged=true,west=true + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=true,north=true,south=false,waterlogged=true,west=false: + appearance: east=true,north=true,south=false,waterlogged=true,west=false + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=true,north=false,south=true,waterlogged=true,west=false: + appearance: east=true,north=false,south=true,waterlogged=true,west=false + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=true,north=false,south=false,waterlogged=true,west=true: + appearance: east=true,north=false,south=false,waterlogged=true,west=true + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=false,north=true,south=true,waterlogged=true,west=false: + appearance: east=false,north=true,south=true,waterlogged=true,west=false + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=false,north=true,south=false,waterlogged=true,west=true: + appearance: east=false,north=true,south=false,waterlogged=true,west=true + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=false,north=false,south=true,waterlogged=true,west=true: + appearance: east=false,north=false,south=true,waterlogged=true,west=true + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=true,north=true,south=true,waterlogged=true,west=false: + appearance: east=true,north=true,south=true,waterlogged=true,west=false + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=true,north=true,south=false,waterlogged=true,west=true: + appearance: east=true,north=true,south=false,waterlogged=true,west=true + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=true,north=false,south=true,waterlogged=true,west=true: + appearance: east=true,north=false,south=true,waterlogged=true,west=true + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=false,north=true,south=true,waterlogged=true,west=true: + appearance: east=false,north=true,south=true,waterlogged=true,west=true + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + east=true,north=true,south=true,waterlogged=true,west=true: + appearance: east=true,north=true,south=true,waterlogged=true,west=true + id: ${internal_id} + settings: + resistance: 1200.0 + burnable: false + fluid-state: water # recipes templates#recipes: default:recipe/planks: diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fence_side.json b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fence_side.json new file mode 100644 index 000000000..2c3c53932 --- /dev/null +++ b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/fence_side.json @@ -0,0 +1,29 @@ +{ + "textures": { + "particle": "#texture" + }, + "elements": [ + { + "from": [6.9989, 11.99835, -0.00495], + "to": [9.0011, 15.00165, 9.00495], + "rotation": {"angle": 0, "axis": "y", "origin": [-0.0088, -0.01485, -0.00495]}, + "faces": { + "east": {"uv": [0, 1, 9, 4], "texture": "#texture"}, + "west": {"uv": [0, 1, 9, 4], "texture": "#texture"}, + "up": {"uv": [7, 0, 9, 9], "texture": "#texture"}, + "down": {"uv": [7, 0, 9, 9], "texture": "#texture"} + } + }, + { + "from": [6.9989, 5.99835, -0.00495], + "to": [9.0011, 9.00165, 9.00495], + "rotation": {"angle": 0, "axis": "y", "origin": [-0.0088, -0.00825, -0.00495]}, + "faces": { + "east": {"uv": [0, 7, 9, 10], "texture": "#texture"}, + "west": {"uv": [0, 7, 9, 10], "texture": "#texture"}, + "up": {"uv": [7, 0, 9, 9], "texture": "#texture"}, + "down": {"uv": [7, 0, 9, 9], "texture": "#texture"} + } + } + ] +} \ No newline at end of file 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 586931ea7..2777d7c88 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 @@ -543,6 +543,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/hami_melon_top.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_slice.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_seeds.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/fence_side.json"); } private TreeMap> updateCachedConfigFiles() { From b2c73852c3f2f8d0314a03e004ca4644dadc08c0 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 08:55:31 +0800 Subject: [PATCH 051/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=85=E6=A0=8F?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/additional-real-blocks.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common-files/src/main/resources/additional-real-blocks.yml b/common-files/src/main/resources/additional-real-blocks.yml index 31bea6787..6ca380ee7 100644 --- a/common-files/src/main/resources/additional-real-blocks.yml +++ b/common-files/src/main/resources/additional-real-blocks.yml @@ -87,4 +87,5 @@ minecraft:redstone_torch: 1 minecraft:redstone_wall_torch: 4 minecraft:pumpkin_stem: 8 minecraft:attached_pumpkin_stem: 4 -minecraft:birch_button: 24 \ No newline at end of file +minecraft:birch_button: 24 +minecraft:oak_fence: 32 \ No newline at end of file From 403880d53151150f291b128cefb8e9e7d6e05f04 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 10:46:23 +0800 Subject: [PATCH 052/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=93=83=E5=A3=B0?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E8=A1=8C=E4=B8=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 留给水晶母岩用 --- .../block/behavior/BukkitBlockBehaviors.java | 2 + .../block/behavior/ChimeBlockBehavior.java | 56 +++++++++++++++++++ .../UnsafeCompositeBlockBehavior.java | 14 +++++ .../LiquidCollisionBlockItemBehavior.java | 4 +- .../plugin/injector/BlockGenerator.java | 17 ++++++ .../reflection/minecraft/CoreReflections.java | 19 +++++-- .../src/main/resources/translations/en.yml | 1 + .../src/main/resources/translations/zh_cn.yml | 1 + .../craftengine/core/block/BlockBehavior.java | 5 +- gradle.properties | 2 +- 10 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java 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 ce5a59520..921fee717 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 @@ -41,6 +41,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK = Key.from("craftengine:face_attached_horizontal_directional_block"); public static final Key STEM_BLOCK = Key.from("craftengine:stem_block"); public static final Key ATTACHED_STEM_BLOCK = Key.from("craftengine:attached_stem_block"); + public static final Key CHIME_BLOCK = Key.from("craftengine:chime_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -80,5 +81,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(FACE_ATTACHED_HORIZONTAL_DIRECTIONAL_BLOCK, FaceAttachedHorizontalDirectionalBlockBehavior.FACTORY); register(STEM_BLOCK, StemBlockBehavior.FACTORY); register(ATTACHED_STEM_BLOCK, AttachedStemBlockBehavior.FACTORY); + register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java new file mode 100644 index 000000000..f008b81e1 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -0,0 +1,56 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.sound.SoundData; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.Callable; + +public class ChimeBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final SoundData hitSound; + private final boolean randomPitch; + private final float randomMultiplier; + + public ChimeBlockBehavior(CustomBlock customBlock, SoundData hitSound, boolean randomPitch, float randomMultiplier) { + super(customBlock); + this.hitSound = hitSound; + this.randomPitch = randomPitch; + this.randomMultiplier = randomMultiplier; + } + + @Override + public void onProjectileHit(Object thisBlock, Object[] args, Callable superMethod) { + Object blockPos = FastNMS.INSTANCE.field$BlockHitResult$blockPos(args[2]); + Object sound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(hitSound.id()), Optional.empty()); + float pitch = hitSound.pitch().get(); + if (randomPitch) { + pitch = pitch + RandomUtils.generateRandomInt(0, 1) * this.randomMultiplier; + } + FastNMS.INSTANCE.method$LevelAccessor$playSound(args[0], null, blockPos, sound, CoreReflections.instance$SoundSource$BLOCKS, hitSound.volume().get(), pitch); + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + SoundData hitSound = SoundData.create(ResourceConfigUtils.requireNonNullOrThrow(arguments.get("hit-sound"), "warning.config.block.behavior.chime.missing_hit_sound"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); + Map randomPitch = ResourceConfigUtils.getAsMapOrNull(arguments.get("random-pitch"), "random-pitch"); + boolean enableRandomPitch = false; + float randomMultiplier = 1f; + if (randomPitch != null) { + enableRandomPitch = true; + randomMultiplier = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("multiplier", 1f), "multiplier"); + } + return new ChimeBlockBehavior(block, hitSound, enableRandomPitch, randomMultiplier); + } + } +} 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 0aab207be..e2671bc94 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 @@ -381,4 +381,18 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior } FallOnBlockBehavior.super.updateEntityMovementAfterFallOn(thisBlock, args, superMethod); } + + @Override + public void stepOn(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.stepOn(thisBlock, args, superMethod); + } + } + + @Override + public void onProjectileHit(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.onProjectileHit(thisBlock, args, superMethod); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java index 051838931..36a62b18d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java @@ -47,7 +47,7 @@ public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior { try { if (player == null) return InteractionResult.FAIL; Object blockHitResult = CoreReflections.method$Item$getPlayerPOVHitResult.invoke(null, world.serverWorld(), player.serverPlayer(), CoreReflections.instance$ClipContext$Fluid$SOURCE_ONLY); - Object blockPos = FastNMS.INSTANCE.field$BlockHitResul$blockPos(blockHitResult); + Object blockPos = FastNMS.INSTANCE.field$BlockHitResult$blockPos(blockHitResult); BlockPos above = new BlockPos(FastNMS.INSTANCE.field$Vec3i$x(blockPos), FastNMS.INSTANCE.field$Vec3i$y(blockPos) + offsetY, FastNMS.INSTANCE.field$Vec3i$z(blockPos)); Direction direction = DirectionUtils.fromNMSDirection(FastNMS.INSTANCE.field$BlockHitResul$direction(blockHitResult)); boolean miss = FastNMS.INSTANCE.field$BlockHitResul$miss(blockHitResult); @@ -59,7 +59,7 @@ public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior { if (miss) { return super.useOnBlock(new UseOnContext(player, hand, BlockHitResult.miss(hitPos, direction, above))); } else { - boolean inside = CoreReflections.field$BlockHitResul$inside.getBoolean(blockHitResult); + boolean inside = CoreReflections.field$BlockHitResult$inside.getBoolean(blockHitResult); return super.useOnBlock(new UseOnContext(player, hand, new BlockHitResult(hitPos, direction, above, inside))); } } catch (Exception e) { 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 ae5e8c670..2b3792085 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 @@ -170,6 +170,9 @@ public final class BlockGenerator { // stepOn .method(ElementMatchers.is(CoreReflections.method$Block$stepOn)) .intercept(MethodDelegation.to(StepOnInterceptor.INSTANCE)) + // onProjectileHit + .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$onProjectileHit)) + .intercept(MethodDelegation.to(OnProjectileHitInterceptor.INSTANCE)) ; // 1.21.5+ if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) { @@ -760,4 +763,18 @@ public final class BlockGenerator { } } } + + public static class OnProjectileHitInterceptor { + public static final OnProjectileHitInterceptor INSTANCE = new OnProjectileHitInterceptor(); + + @RuntimeType + public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + holder.value().onProjectileHit(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run onProjectileHit", e); + } + } + } } \ No newline at end of file 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 0cae0070e..04fd97cec 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 @@ -2559,19 +2559,19 @@ public final class CoreReflections { ReflectionUtils.getMethod(clazz$BlockHitResult, clazz$BlockHitResult, clazz$BlockPos) ); - public static final Field field$BlockHitResul$blockPos = requireNonNull( + public static final Field field$BlockHitResult$blockPos = requireNonNull( ReflectionUtils.getDeclaredField(clazz$BlockHitResult, clazz$BlockPos, 0) ); - public static final Field field$BlockHitResul$direction = requireNonNull( + public static final Field field$BlockHitResult$direction = requireNonNull( ReflectionUtils.getDeclaredField(clazz$BlockHitResult, clazz$Direction, 0) ); - public static final Field field$BlockHitResul$miss = requireNonNull( + public static final Field field$BlockHitResult$miss = requireNonNull( ReflectionUtils.getDeclaredField(clazz$BlockHitResult, boolean.class, 0) ); - public static final Field field$BlockHitResul$inside = requireNonNull( + public static final Field field$BlockHitResult$inside = requireNonNull( ReflectionUtils.getDeclaredField(clazz$BlockHitResult, boolean.class, 1) ); @@ -4418,4 +4418,15 @@ public final class CoreReflections { public static final Method method$BlockStateBase$isBlock = requireNonNull( ReflectionUtils.getDeclaredMethod(clazz$BlockStateBase, boolean.class, new String[]{"is", "a"}, clazz$Block) ); + + public static final Class clazz$Projectile = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.entity.projectile.IProjectile", + "world.entity.projectile.Projectile" + ) + ); + + public static final Method method$BlockBehaviour$onProjectileHit = requireNonNull( + ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"onProjectileHit", "a"}, clazz$Level, clazz$BlockState, clazz$BlockHitResult, clazz$Projectile) + ); } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 3abacd999..6c88ca4a0 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -336,6 +336,7 @@ warning.config.block.behavior.stem.missing_attached_stem: "Issue found i warning.config.block.behavior.attached_stem.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'attached_stem_block' behavior." warning.config.block.behavior.attached_stem.missing_fruit: "Issue found in file - The block '' is missing the required 'fruit' argument for 'attached_stem_block' behavior." warning.config.block.behavior.attached_stem.missing_stem: "Issue found in file - The block '' is missing the required 'stem' argument for 'attached_stem_block' behavior." +warning.config.block.behavior.chime.missing_hit_sound: "Issue found in file - The block '' is missing the required 'hit-sound' argument for 'chime_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.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." 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: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 6f5171988..4072ac068 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -330,6 +330,7 @@ warning.config.block.behavior.stem.missing_attached_stem: "在文件 在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'facing' 属性" warning.config.block.behavior.attached_stem.missing_fruit: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项" warning.config.block.behavior.attached_stem.missing_stem: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项" +warning.config.block.behavior.chime.missing_hit_sound: "在文件 发现问题 - 方块 '' 的 'chime_block' 行为缺少必需的 'hit-sound' 选项" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" 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 e94b5322e..738dd94ea 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 @@ -181,7 +181,10 @@ public abstract class BlockBehavior { // Level level, BlockPos pos, BlockState state, Entity entity public void stepOn(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - superMethod.call(); + } + + // Level level, BlockState state, BlockHitResult hit, Projectile projectile + public void onProjectileHit(Object thisBlock, Object[] args, Callable superMethod) throws Exception { } public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { diff --git a/gradle.properties b/gradle.properties index 5cae0308f..e5de2af92 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.95 +nms_helper_version=1.0.96 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1 From aad894c5f0e8d122da10bc9de8249c77e3d935ae Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 15:35:41 +0800 Subject: [PATCH 053/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=98=91=E8=8F=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/BuddingBlockBehavior.java | 99 +++++++++++ .../block/behavior/BukkitBlockBehaviors.java | 2 + .../reflection/minecraft/CoreReflections.java | 5 + .../minecraft/MBlockStateProperties.java | 10 ++ common-files/src/main/resources/mappings.yml | 24 +-- .../default/configuration/blocks/mushroom.yml | 155 ++++++++++++++++++ .../configuration/blocks/palm_tree.yml | 12 ++ .../default/configuration/categories.yml | 6 +- .../resources/default/configuration/i18n.yml | 16 ++ .../default/configuration/items/gui_head.yml | 2 + .../default/configuration/templates.yml | 37 +++++ .../{mushroom_2.json => large_mushroom.json} | 23 ++- .../{mushroom_3.json => medium_mushroom.json} | 23 ++- .../{mushroom_1.json => small_mushroom.json} | 23 ++- .../core/block/properties/Property.java | 6 + .../core/pack/AbstractPackManager.java | 5 + 16 files changed, 432 insertions(+), 16 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BuddingBlockBehavior.java create mode 100644 common-files/src/main/resources/resources/default/configuration/blocks/mushroom.yml rename common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/{mushroom_2.json => large_mushroom.json} (89%) rename common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/{mushroom_3.json => medium_mushroom.json} (82%) rename common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/{mushroom_1.json => small_mushroom.json} (79%) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BuddingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BuddingBlockBehavior.java new file mode 100644 index 000000000..a42367d2d --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BuddingBlockBehavior.java @@ -0,0 +1,99 @@ +package net.momirealms.craftengine.bukkit.block.behavior; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.*; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.bukkit.util.DirectionUtils; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.block.properties.BooleanProperty; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.util.*; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; + +public class BuddingBlockBehavior extends BukkitBlockBehavior { + public static final Factory FACTORY = new Factory(); + private final int growthChance; + private final List blocks; + + public BuddingBlockBehavior(CustomBlock customBlock, int growthChance, List blocks) { + super(customBlock); + this.growthChance = growthChance; + this.blocks = blocks; + } + + @Override + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + if (RandomUtils.generateRandomInt(0, this.growthChance) != 0) return; + Object nmsDirection = CoreReflections.instance$Direction$values[RandomUtils.generateRandomInt(0, 6)]; + Direction direction = DirectionUtils.fromNMSDirection(nmsDirection); + Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(args[2], nmsDirection); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(args[1], blockPos); + if (canClusterGrowAtState(blockState)) { + Key blockId = blocks.getFirst(); + CustomBlock firstBlock = BukkitBlockManager.instance().blockById(blockId).orElse(null); + placeWithPropertyBlock(firstBlock, blockId, direction, nmsDirection, args[1], blockPos, blockState); + } else { + Key blockId = BlockStateUtils.getOptionalCustomBlockState(blockState) + .map(it -> it.owner().value().id()) + .orElseGet(() -> BlockStateUtils.getBlockOwnerIdFromState(blockState)); + int blockIdIndex = blocks.indexOf(blockId); + if (blockIdIndex < 0 || blockIdIndex == blocks.size() - 1) return; + Key nextBlockId = blocks.get(blockIdIndex + 1); + CustomBlock nextBlock = BukkitBlockManager.instance().blockById(nextBlockId).orElse(null); + placeWithPropertyBlock(nextBlock, nextBlockId, direction, nmsDirection, args[1], blockPos, blockState); + } + } + + @SuppressWarnings("unchecked") + private void placeWithPropertyBlock(CustomBlock customBlock, Key blockId, Direction direction, Object nmsDirection, Object level, Object blockPos, Object blockState) { + if (customBlock != null) { + ImmutableBlockState newState = customBlock.defaultState(); + Property facing = customBlock.getProperty("facing"); + if (facing != null) { + if (facing.valueClass() == Direction.class) { + newState = newState.with((Property) facing, direction); + } else if (facing.valueClass() == HorizontalDirection.class) { + if (!direction.axis().isHorizontal()) return; + newState = newState.with((Property) facing, direction.toHorizontalDirection()); + } + } + BooleanProperty waterlogged = (BooleanProperty) customBlock.getProperty("waterlogged"); + if (waterlogged != null) { + newState = newState.with(waterlogged, FastNMS.INSTANCE.method$FluidState$getType(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(blockState)) == MFluids.WATER); + } + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState.customBlockState().literalObject(), 3); + } else if (blockId.namespace().equals("minecraft")) { + Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", blockId.value())); + if (block == null) return; + Object newState = FastNMS.INSTANCE.method$Block$defaultState(block); + newState = FastNMS.INSTANCE.method$StateHolder$trySetValue(newState, MBlockStateProperties.WATERLOGGED, FastNMS.INSTANCE.method$FluidState$getType(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(blockState)) == MFluids.WATER); + newState = FastNMS.INSTANCE.method$StateHolder$trySetValue(newState, MBlockStateProperties.FACING, (Comparable) nmsDirection); + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, blockPos, newState, 3); + } + } + + public static boolean canClusterGrowAtState(Object state) { + return FastNMS.INSTANCE.method$BlockStateBase$isAir(state) + || FastNMS.INSTANCE.method$BlockStateBase$isBlock(state, MBlocks.WATER) + && FastNMS.INSTANCE.field$FluidState$amount(FastNMS.INSTANCE.field$BlockBehaviour$BlockStateBase$fluidState(state)) == 8; + } + + public static class Factory implements BlockBehaviorFactory { + + @Override + public BlockBehavior create(CustomBlock block, Map arguments) { + int growthChance = ResourceConfigUtils.getAsInt(arguments.getOrDefault("growth-chance", 5), "growth-chance"); + List blocks = new ObjectArrayList<>(); + MiscUtils.getAsStringList(arguments.get("blocks")).forEach(s -> blocks.add(Key.of(s))); + return new BuddingBlockBehavior(block, growthChance, blocks); + } + } +} 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 921fee717..000ecaccd 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 @@ -42,6 +42,7 @@ public class BukkitBlockBehaviors extends BlockBehaviors { public static final Key STEM_BLOCK = Key.from("craftengine:stem_block"); public static final Key ATTACHED_STEM_BLOCK = Key.from("craftengine:attached_stem_block"); public static final Key CHIME_BLOCK = Key.from("craftengine:chime_block"); + public static final Key BUDDING_BLOCK = Key.from("craftengine:budding_block"); public static void init() { register(EMPTY, (block, args) -> EmptyBlockBehavior.INSTANCE); @@ -82,5 +83,6 @@ public class BukkitBlockBehaviors extends BlockBehaviors { register(STEM_BLOCK, StemBlockBehavior.FACTORY); register(ATTACHED_STEM_BLOCK, AttachedStemBlockBehavior.FACTORY); register(CHIME_BLOCK, ChimeBlockBehavior.FACTORY); + register(BUDDING_BLOCK, BuddingBlockBehavior.FACTORY); } } 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 04fd97cec..bbc030da9 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 @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.minecraft; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.gson.JsonElement; import com.mojang.serialization.Codec; import com.mojang.serialization.DynamicOps; @@ -4429,4 +4430,8 @@ public final class CoreReflections { public static final Method method$BlockBehaviour$onProjectileHit = requireNonNull( ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"onProjectileHit", "a"}, clazz$Level, clazz$BlockState, clazz$BlockHitResult, clazz$Projectile) ); + + public static final Field field$EnumProperty$values = requireNonNull( + ReflectionUtils.getDeclaredField(clazz$EnumProperty, VersionHelper.isOrAbove1_21_2() ? List.class : ImmutableSet.class, 0) + ); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlockStateProperties.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlockStateProperties.java index 0bec500a3..452f4efb3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlockStateProperties.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/MBlockStateProperties.java @@ -4,24 +4,34 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitExcepti import java.lang.reflect.Field; import java.lang.reflect.Modifier; +import java.util.Collection; import static java.util.Objects.requireNonNull; public final class MBlockStateProperties { public static final Object WATERLOGGED; + public static final Object FACING; static { try { Object waterlogged = null; + Object facing = null; for (Field field : CoreReflections.clazz$BlockStateProperties.getDeclaredFields()) { if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers())) { Object instance = field.get(null); if (CoreReflections.clazz$Property.isInstance(instance) && CoreReflections.field$Property$name.get(instance).equals("waterlogged")) { waterlogged = instance; + } else if (CoreReflections.clazz$EnumProperty.isInstance(instance) && CoreReflections.field$Property$name.get(instance).equals("facing")) { + @SuppressWarnings("unchecked") + Collection values = (Collection) CoreReflections.field$EnumProperty$values.get(instance); + if (values.size() == CoreReflections.instance$Direction$values.length) { + facing = instance; + } } } } WATERLOGGED = requireNonNull(waterlogged); + FACING = requireNonNull(facing); } catch (ReflectiveOperationException e) { throw new ReflectionInitException("Failed to init MBlockStateProperties", e); } diff --git a/common-files/src/main/resources/mappings.yml b/common-files/src/main/resources/mappings.yml index d3f9f58f2..a3a0b28b1 100644 --- a/common-files/src/main/resources/mappings.yml +++ b/common-files/src/main/resources/mappings.yml @@ -4340,10 +4340,10 @@ minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pres # minecraft:dead_bubble_coral[waterlogged=true]: minecraft:bubble_coral[waterlogged=true] # minecraft:dead_bubble_coral_fan[waterlogged=false]: minecraft:bubble_coral_fan[waterlogged=false] # minecraft:dead_bubble_coral_fan[waterlogged=true]: minecraft:bubble_coral_fan[waterlogged=true] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=east] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=north] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=south] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=west] +minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=east] +minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=north] +minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=south] +minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=west] # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=east] # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=south] @@ -4352,10 +4352,10 @@ minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pres # minecraft:dead_fire_coral[waterlogged=true]: minecraft:fire_coral[waterlogged=true] # minecraft:dead_fire_coral_fan[waterlogged=false]: minecraft:fire_coral_fan[waterlogged=false] # minecraft:dead_fire_coral_fan[waterlogged=true]: minecraft:fire_coral_fan[waterlogged=true] -# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=east] -# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=north] -# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=south] -# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=west] +minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=east] +minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=north] +minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=south] +minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=west] # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=east] # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=south] @@ -4364,10 +4364,10 @@ minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pres # minecraft:dead_horn_coral[waterlogged=true]: minecraft:horn_coral[waterlogged=true] # minecraft:dead_horn_coral_fan[waterlogged=false]: minecraft:horn_coral_fan[waterlogged=false] # minecraft:dead_horn_coral_fan[waterlogged=true]: minecraft:horn_coral_fan[waterlogged=true] -# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=east] -# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=north] -# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=south] -# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=west] +minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=east] +minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=north] +minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=south] +minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=west] # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=east] # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=south] diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/mushroom.yml b/common-files/src/main/resources/resources/default/configuration/blocks/mushroom.yml new file mode 100644 index 000000000..436b71872 --- /dev/null +++ b/common-files/src/main/resources/resources/default/configuration/blocks/mushroom.yml @@ -0,0 +1,155 @@ +items: + default:infected_palm_log: + material: nether_brick + custom-model-data: 3025 + settings: + fuel-time: 300 + tags: + - default:palm_logs + - minecraft:logs + - minecraft:logs_that_burn + data: + item-name: + model: + type: minecraft:model + path: minecraft:item/custom/palm_log + generation: + parent: minecraft:block/custom/palm_log + behavior: + type: block_item + block: default:infected_palm_log + default:small_mushroom: + material: nether_brick + custom-model-data: 3026 + data: + item-name: + model: + type: minecraft:model + path: minecraft:item/custom/small_mushroom + generation: + parent: minecraft:block/custom/small_mushroom + behavior: + type: block_item + block: default:small_mushroom + default:medium_mushroom: + material: nether_brick + custom-model-data: 3027 + data: + item-name: + model: + type: minecraft:model + path: minecraft:item/custom/medium_mushroom + generation: + parent: minecraft:block/custom/medium_mushroom + behavior: + type: block_item + block: default:medium_mushroom + default:large_mushroom: + material: nether_brick + custom-model-data: 3028 + data: + item-name: + model: + type: minecraft:model + path: minecraft:item/custom/large_mushroom + generation: + parent: minecraft:block/custom/large_mushroom + behavior: + type: block_item + block: default:large_mushroom + +blocks: + default:infected_palm_log: + behavior: + - type: strippable_block + stripped: default:stripped_palm_log + - type: budding_block + growth-chance: 5 + blocks: + - default:small_mushroom + - default:medium_mushroom + - default:large_mushroom + loot: + template: default:loot_table/self + settings: + template: default:settings/wood + overrides: + is-randomly-ticking: true + map-color: 2 + states: + template: default:block_state/pillar + arguments: + base_block: note_block + texture_top_path: minecraft:block/custom/palm_log_top + texture_side_path: minecraft:block/custom/palm_log + model_vertical_path: minecraft:block/custom/palm_log + model_horizontal_path: minecraft:block/custom/palm_log_horizontal + vanilla_id: + type: self_increase_int + from: 31 + to: 33 + internal_id: + type: self_increase_int + from: 31 + to: 33 + default:small_mushroom: + settings: + template: + - default:sound/crop + - default:hardness/none + overrides: + push-reaction: destroy + map-color: 26 + luminance: 1 + tags: + - minecraft:enderman_holdable + - minecraft:replaceable_by_mushrooms + behavior: + type: directional_attached_block + states: + template: default:block_state/mushroom + arguments: + base_block: dead_bubble_coral_wall_fan + model_path: minecraft:block/custom/small_mushroom + default:medium_mushroom: + behavior: + type: directional_attached_block + settings: + template: + - default:sound/crop + - default:hardness/none + overrides: + push-reaction: destroy + map-color: 26 + luminance: 1 + tags: + - minecraft:enderman_holdable + - minecraft:replaceable_by_mushrooms + states: + template: default:block_state/mushroom + arguments: + base_block: dead_horn_coral_wall_fan + model_path: minecraft:block/custom/medium_mushroom + default:large_mushroom: + loot: + template: default:loot_table/basic + arguments: + item: minecraft:brown_mushroom + behavior: + type: directional_attached_block + settings: + template: + - default:sound/crop + - default:hardness/none + overrides: + push-reaction: destroy + map-color: 26 + luminance: 1 + tags: + - minecraft:enderman_holdable + - minecraft:replaceable_by_mushrooms + states: + template: default:block_state/mushroom + arguments: + base_block: dead_fire_coral_wall_fan + model_path: minecraft:block/custom/large_mushroom diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 47523c47b..2589481da 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -297,6 +297,8 @@ blocks: template: default:loot_table/self settings: template: default:settings/wood + overrides: + map-color: 2 states: template: default:block_state/pillar arguments: @@ -318,6 +320,8 @@ blocks: template: default:loot_table/self settings: template: default:settings/wood + overrides: + map-color: 2 states: template: default:block_state/pillar arguments: @@ -342,6 +346,8 @@ blocks: template: default:loot_table/self settings: template: default:settings/wood + overrides: + map-color: 2 states: template: default:block_state/pillar arguments: @@ -363,6 +369,8 @@ blocks: template: default:loot_table/self settings: template: default:settings/wood + overrides: + map-color: 2 states: template: default:block_state/pillar arguments: @@ -382,6 +390,8 @@ blocks: default:palm_planks: settings: template: default:settings/planks + overrides: + map-color: 2 loot: template: default:loot_table/self state: @@ -437,6 +447,8 @@ blocks: sapling: default:palm_sapling settings: template: default:settings/leaves + overrides: + map-color: 19 states: template: default:block_state/leaves arguments: diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 2d911abe4..f73618373 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -29,6 +29,7 @@ categories: - default:palm_pressure_plate - default:palm_button - default:palm_fence + - default:infected_palm_log default:topaz: name: <#FF8C00> hidden: true @@ -83,4 +84,7 @@ categories: - default:amethyst_torch - default:hami_melon_seeds - default:hami_melon_slice - - default:hami_melon \ No newline at end of file + - default:hami_melon + - default:small_mushroom + - default:medium_mushroom + - default:large_mushroom \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index 71d6e9e30..b8ad2e75d 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -54,6 +54,10 @@ i18n: item.hami_melon_seeds: Hami Melon Seeds item.palm_button: Palm Button item.palm_fence: Palm Fence + item.infected_palm_log: Infected Palm Log + item.small_mushroom: Small Mushroom + item.medium_mushroom: Medium Mushroom + item.large_mushroom: Large Mushroom category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -117,6 +121,10 @@ i18n: item.hami_melon_seeds: 哈密瓜种子 item.palm_button: 棕榈木按钮 item.palm_fence: 棕榈木栅栏 + item.infected_palm_log: 菌蚀棕榈原木 + item.small_mushroom: 小型蘑菇 + item.medium_mushroom: 中型蘑菇 + item.large_mushroom: 大型蘑菇 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 @@ -164,6 +172,10 @@ lang: block_name:default:default:attached_hami_melon_stem: Hami Melon Stem block_name:default:palm_button: Palm Button block_name:default:palm_fence: Palm Fence + block_name:default:infected_palm_log: Infected Palm Log + block_name:default:small_mushroom: Small Mushroom + block_name:default:medium_mushroom: Medium Mushroom + block_name:default:large_mushroom: Large Mushroom zh_cn: block_name:default:chinese_lantern: 灯笼 block_name:default:netherite_anvil: 下界合金砧 @@ -199,3 +211,7 @@ lang: block_name:default:default:attached_hami_melon_stem: 哈密瓜茎 block_name:default:palm_button: 棕榈木按钮 block_name:default:palm_fence: 棕榈木栅栏 + block_name:default:infected_palm_log: 菌蚀棕榈原木 + block_name:default:small_mushroom: 小型蘑菇 + block_name:default:medium_mushroom: 中型蘑菇 + block_name:default:large_mushroom: 大型蘑菇 diff --git a/common-files/src/main/resources/resources/default/configuration/items/gui_head.yml b/common-files/src/main/resources/resources/default/configuration/items/gui_head.yml index effc996c8..9a6b67a8b 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/gui_head.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/gui_head.yml @@ -2,6 +2,7 @@ items: default:gui_head_size_1: material: player_head custom-model-data: 1000 + item-model: default:gui_head_size_1 model: type: minecraft:special path: minecraft:item/custom/gui_head_size_1 @@ -17,6 +18,7 @@ items: default:gui_head_size_4: material: player_head custom-model-data: 1001 + item-model: default:gui_head_size_4 model: type: minecraft:special path: minecraft:item/custom/gui_head_size_4 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 fa284b068..20392707e 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -3930,6 +3930,43 @@ templates#block_states: resistance: 1200.0 burnable: false fluid-state: water + default:block_state/mushroom: + properties: + facing: + type: horizontal_direction + appearances: + north: + state: ${base_block}[waterlogged=false,facing=north] + model: + path: ${model_path} + east: + state: ${base_block}[waterlogged=false,facing=east] + model: + path: ${model_path} + y: 90 + west: + state: ${base_block}[waterlogged=false,facing=west] + model: + path: ${model_path} + y: 270 + south: + state: ${base_block}[waterlogged=false,facing=south] + model: + path: ${model_path} + y: 180 + variants: + facing=north: + appearance: north + id: 0 + facing=east: + appearance: east + id: 1 + facing=west: + appearance: west + id: 2 + facing=south: + appearance: south + id: 3 # recipes templates#recipes: default:recipe/planks: diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/mushroom_2.json b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/large_mushroom.json similarity index 89% rename from common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/mushroom_2.json rename to common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/large_mushroom.json index 5c75b3c6e..356812b0e 100644 --- a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/mushroom_2.json +++ b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/large_mushroom.json @@ -1,6 +1,7 @@ { "textures": { - "0": "block/custom/mushroom" + "0": "block/custom/mushroom", + "particle": "block/custom/mushroom" }, "elements": [ { @@ -146,6 +147,26 @@ "fixed": { "translation": [0, 0, -16], "scale": [2, 2, 2] + }, + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 2.5, 1], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 2.5, 1], + "scale": [0.4, 0.4, 0.4] } } } \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/mushroom_3.json b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/medium_mushroom.json similarity index 82% rename from common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/mushroom_3.json rename to common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/medium_mushroom.json index 79459425c..e00ea901d 100644 --- a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/mushroom_3.json +++ b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/medium_mushroom.json @@ -1,6 +1,7 @@ { "textures": { - "0": "block/custom/mushroom" + "0": "block/custom/mushroom", + "particle": "block/custom/mushroom" }, "elements": [ { @@ -81,6 +82,26 @@ "fixed": { "translation": [0, 0, -16], "scale": [2, 2, 2] + }, + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 2.5, 1], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 2.5, 1], + "scale": [0.4, 0.4, 0.4] } } } \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/mushroom_1.json b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/small_mushroom.json similarity index 79% rename from common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/mushroom_1.json rename to common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/small_mushroom.json index f70b470fe..bbc245d23 100644 --- a/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/mushroom_1.json +++ b/common-files/src/main/resources/resources/default/resourcepack/assets/minecraft/models/block/custom/small_mushroom.json @@ -1,7 +1,8 @@ { "texture_size": [32, 32], "textures": { - "0": "block/custom/mushroom" + "0": "block/custom/mushroom", + "particle": "block/custom/mushroom" }, "elements": [ { @@ -69,6 +70,26 @@ "fixed": { "translation": [0, 0, -16.25], "scale": [2, 2, 2] + }, + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 2.5, 1], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 45, 0], + "translation": [-1.5, 2.5, 1], + "scale": [0.4, 0.4, 0.4] } } } \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java index 84bbfda65..8ff91b9a8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.block.properties; +import com.google.common.base.MoreObjects; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; @@ -167,4 +168,9 @@ public abstract class Property> { public static > String formatValue(Property property, Comparable value) { return property.valueName((T) value); } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this).add("name", this.name).add("clazz", this.clazz).add("values", this.possibleValues()).toString(); + } } 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 2777d7c88..91b25f19c 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 @@ -432,6 +432,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/configuration/blocks/netherite_anvil.yml"); plugin.saveResource("resources/default/configuration/blocks/amethyst_torch.yml"); plugin.saveResource("resources/default/configuration/blocks/hami_melon.yml"); + plugin.saveResource("resources/default/configuration/blocks/mushroom.yml"); // assets plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/font/image/emojis.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/chinese_lantern.png"); @@ -544,6 +545,10 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_slice.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_seeds.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/fence_side.json"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/mushroom.png"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/small_mushroom.json"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/medium_mushroom.json"); + plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/large_mushroom.json"); } private TreeMap> updateCachedConfigFiles() { From 98ef6441888c3e71e89b50bf0ee4c903e31ef848 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 15:43:44 +0800 Subject: [PATCH 054/125] =?UTF-8?q?=E8=A1=A5=E6=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/default/configuration/blocks/palm_tree.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 2589481da..789f9768a 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -257,6 +257,7 @@ items: texture: minecraft:block/custom/palm_planks default:palm_fence: material: nether_brick + custom-model-data: 1018 data: item-name: model: @@ -271,6 +272,7 @@ items: block: default:palm_fence default:palm_fence_post: material: nether_brick + custom-model-data: 1019 model: type: minecraft:model path: minecraft:block/custom/palm_fence_post @@ -280,6 +282,7 @@ items: texture: minecraft:block/custom/palm_planks default:palm_fence_side: material: nether_brick + custom-model-data: 1020 model: type: minecraft:model path: minecraft:block/custom/palm_fence_side @@ -751,6 +754,8 @@ blocks: from: 0 to: 23 default:palm_fence: + loot: + template: default:loot_table/self settings: template: - default:hardness/planks From 10dbf3d590a6c583397249ded179c2533e16ecaf Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 16:02:36 +0800 Subject: [PATCH 055/125] =?UTF-8?q?=E5=88=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/mappings.yml | 24 +-- .../configuration/blocks/hami_melon.yml | 104 ------------ .../default/configuration/blocks/mushroom.yml | 155 ------------------ .../default/configuration/categories.yml | 6 +- .../core/pack/AbstractPackManager.java | 5 - 5 files changed, 13 insertions(+), 281 deletions(-) delete mode 100644 common-files/src/main/resources/resources/default/configuration/blocks/mushroom.yml diff --git a/common-files/src/main/resources/mappings.yml b/common-files/src/main/resources/mappings.yml index a3a0b28b1..d3f9f58f2 100644 --- a/common-files/src/main/resources/mappings.yml +++ b/common-files/src/main/resources/mappings.yml @@ -4340,10 +4340,10 @@ minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pres # minecraft:dead_bubble_coral[waterlogged=true]: minecraft:bubble_coral[waterlogged=true] # minecraft:dead_bubble_coral_fan[waterlogged=false]: minecraft:bubble_coral_fan[waterlogged=false] # minecraft:dead_bubble_coral_fan[waterlogged=true]: minecraft:bubble_coral_fan[waterlogged=true] -minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=east] -minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=north] -minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=south] -minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=west] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=east] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=north] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=south] +# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=west] # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=east] # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=south] @@ -4352,10 +4352,10 @@ minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=west]: minecraft:b # minecraft:dead_fire_coral[waterlogged=true]: minecraft:fire_coral[waterlogged=true] # minecraft:dead_fire_coral_fan[waterlogged=false]: minecraft:fire_coral_fan[waterlogged=false] # minecraft:dead_fire_coral_fan[waterlogged=true]: minecraft:fire_coral_fan[waterlogged=true] -minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=east] -minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=north] -minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=south] -minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=west] +# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=east] +# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=north] +# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=south] +# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=west] # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=east] # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=south] @@ -4364,10 +4364,10 @@ minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=west]: minecraft:fir # minecraft:dead_horn_coral[waterlogged=true]: minecraft:horn_coral[waterlogged=true] # minecraft:dead_horn_coral_fan[waterlogged=false]: minecraft:horn_coral_fan[waterlogged=false] # minecraft:dead_horn_coral_fan[waterlogged=true]: minecraft:horn_coral_fan[waterlogged=true] -minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=east] -minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=north] -minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=south] -minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=west] +# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=east] +# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=north] +# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=south] +# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=west] # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=east] # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=north] # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=south] diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml index 356d62b63..f9407d1f2 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml @@ -96,95 +96,6 @@ blocks: south_texture: minecraft:block/custom/hami_melon west_texture: minecraft:block/custom/hami_melon default:hami_melon_stem: - loot: - pools: - - rolls: 1 - entries: - - type: item - item: default:hami_melon_seeds - functions: - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 0 - count: - type: binomial - extra: 3 - probability: 0.06666667 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 1 - count: - type: binomial - extra: 3 - probability: 0.13333334 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 2 - count: - type: binomial - extra: 3 - probability: 0.2 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 3 - count: - type: binomial - extra: 3 - probability: 0.26666668 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 4 - count: - type: binomial - extra: 3 - probability: 0.33333334 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 5 - count: - type: binomial - extra: 3 - probability: 0.4 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 6 - count: - type: binomial - extra: 3 - probability: 0.46666667 - - type: set_count - add: false - conditions: - - type: match_block_property - properties: - age: 7 - count: - type: binomial - extra: 3 - probability: 0.53333336 - functions: - - type: explosion_decay settings: template: - default:sound/stem_crop @@ -256,21 +167,6 @@ blocks: appearance: age=7 id: 7 default:attached_hami_melon_stem: - loot: - pools: - - rolls: 1 - entries: - - type: item - item: default:hami_melon_seeds - functions: - - type: set_count - add: false - count: - type: binomial - extra: 3 - probability: 0.53333336 - functions: - - type: explosion_decay settings: template: - default:sound/stem_crop diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/mushroom.yml b/common-files/src/main/resources/resources/default/configuration/blocks/mushroom.yml deleted file mode 100644 index 436b71872..000000000 --- a/common-files/src/main/resources/resources/default/configuration/blocks/mushroom.yml +++ /dev/null @@ -1,155 +0,0 @@ -items: - default:infected_palm_log: - material: nether_brick - custom-model-data: 3025 - settings: - fuel-time: 300 - tags: - - default:palm_logs - - minecraft:logs - - minecraft:logs_that_burn - data: - item-name: - model: - type: minecraft:model - path: minecraft:item/custom/palm_log - generation: - parent: minecraft:block/custom/palm_log - behavior: - type: block_item - block: default:infected_palm_log - default:small_mushroom: - material: nether_brick - custom-model-data: 3026 - data: - item-name: - model: - type: minecraft:model - path: minecraft:item/custom/small_mushroom - generation: - parent: minecraft:block/custom/small_mushroom - behavior: - type: block_item - block: default:small_mushroom - default:medium_mushroom: - material: nether_brick - custom-model-data: 3027 - data: - item-name: - model: - type: minecraft:model - path: minecraft:item/custom/medium_mushroom - generation: - parent: minecraft:block/custom/medium_mushroom - behavior: - type: block_item - block: default:medium_mushroom - default:large_mushroom: - material: nether_brick - custom-model-data: 3028 - data: - item-name: - model: - type: minecraft:model - path: minecraft:item/custom/large_mushroom - generation: - parent: minecraft:block/custom/large_mushroom - behavior: - type: block_item - block: default:large_mushroom - -blocks: - default:infected_palm_log: - behavior: - - type: strippable_block - stripped: default:stripped_palm_log - - type: budding_block - growth-chance: 5 - blocks: - - default:small_mushroom - - default:medium_mushroom - - default:large_mushroom - loot: - template: default:loot_table/self - settings: - template: default:settings/wood - overrides: - is-randomly-ticking: true - map-color: 2 - states: - template: default:block_state/pillar - arguments: - base_block: note_block - texture_top_path: minecraft:block/custom/palm_log_top - texture_side_path: minecraft:block/custom/palm_log - model_vertical_path: minecraft:block/custom/palm_log - model_horizontal_path: minecraft:block/custom/palm_log_horizontal - vanilla_id: - type: self_increase_int - from: 31 - to: 33 - internal_id: - type: self_increase_int - from: 31 - to: 33 - default:small_mushroom: - settings: - template: - - default:sound/crop - - default:hardness/none - overrides: - push-reaction: destroy - map-color: 26 - luminance: 1 - tags: - - minecraft:enderman_holdable - - minecraft:replaceable_by_mushrooms - behavior: - type: directional_attached_block - states: - template: default:block_state/mushroom - arguments: - base_block: dead_bubble_coral_wall_fan - model_path: minecraft:block/custom/small_mushroom - default:medium_mushroom: - behavior: - type: directional_attached_block - settings: - template: - - default:sound/crop - - default:hardness/none - overrides: - push-reaction: destroy - map-color: 26 - luminance: 1 - tags: - - minecraft:enderman_holdable - - minecraft:replaceable_by_mushrooms - states: - template: default:block_state/mushroom - arguments: - base_block: dead_horn_coral_wall_fan - model_path: minecraft:block/custom/medium_mushroom - default:large_mushroom: - loot: - template: default:loot_table/basic - arguments: - item: minecraft:brown_mushroom - behavior: - type: directional_attached_block - settings: - template: - - default:sound/crop - - default:hardness/none - overrides: - push-reaction: destroy - map-color: 26 - luminance: 1 - tags: - - minecraft:enderman_holdable - - minecraft:replaceable_by_mushrooms - states: - template: default:block_state/mushroom - arguments: - base_block: dead_fire_coral_wall_fan - model_path: minecraft:block/custom/large_mushroom diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index f73618373..2d911abe4 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -29,7 +29,6 @@ categories: - default:palm_pressure_plate - default:palm_button - default:palm_fence - - default:infected_palm_log default:topaz: name: <#FF8C00> hidden: true @@ -84,7 +83,4 @@ categories: - default:amethyst_torch - default:hami_melon_seeds - default:hami_melon_slice - - default:hami_melon - - default:small_mushroom - - default:medium_mushroom - - default:large_mushroom \ No newline at end of file + - default:hami_melon \ No newline at end of file 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 91b25f19c..2777d7c88 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 @@ -432,7 +432,6 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/configuration/blocks/netherite_anvil.yml"); plugin.saveResource("resources/default/configuration/blocks/amethyst_torch.yml"); plugin.saveResource("resources/default/configuration/blocks/hami_melon.yml"); - plugin.saveResource("resources/default/configuration/blocks/mushroom.yml"); // assets plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/font/image/emojis.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/chinese_lantern.png"); @@ -545,10 +544,6 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_slice.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/item/custom/hami_melon_seeds.png"); plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/fence_side.json"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/block/custom/mushroom.png"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/small_mushroom.json"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/medium_mushroom.json"); - plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/large_mushroom.json"); } private TreeMap> updateCachedConfigFiles() { From d522cf105dd2d7cb124c6129c1f648ed2cbe5cfc Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 16:31:48 +0800 Subject: [PATCH 056/125] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/ChimeBlockBehavior.java | 37 +- .../configuration/blocks/palm_tree.yml | 936 ++++++++---------- .../resources/default/configuration/i18n.yml | 16 - .../core/block/properties/Property.java | 2 +- 4 files changed, 437 insertions(+), 554 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java index f008b81e1..b7897e76a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -7,50 +7,43 @@ import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.sound.SoundData; +import net.momirealms.craftengine.core.util.Pair; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; public class ChimeBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); - private final SoundData hitSound; - private final boolean randomPitch; - private final float randomMultiplier; + private final List> hitSounds; - public ChimeBlockBehavior(CustomBlock customBlock, SoundData hitSound, boolean randomPitch, float randomMultiplier) { + public ChimeBlockBehavior(CustomBlock customBlock, List> hitSounds) { super(customBlock); - this.hitSound = hitSound; - this.randomPitch = randomPitch; - this.randomMultiplier = randomMultiplier; + this.hitSounds = hitSounds; } @Override public void onProjectileHit(Object thisBlock, Object[] args, Callable superMethod) { + Pair hitSound = hitSounds.get(RandomUtils.generateRandomInt(0, hitSounds.size())); Object blockPos = FastNMS.INSTANCE.field$BlockHitResult$blockPos(args[2]); - Object sound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(hitSound.id()), Optional.empty()); - float pitch = hitSound.pitch().get(); - if (randomPitch) { - pitch = pitch + RandomUtils.generateRandomInt(0, 1) * this.randomMultiplier; - } - FastNMS.INSTANCE.method$LevelAccessor$playSound(args[0], null, blockPos, sound, CoreReflections.instance$SoundSource$BLOCKS, hitSound.volume().get(), pitch); + Object sound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(hitSound.left().id()), Optional.empty()); + float pitch = hitSound.left().pitch().get() + RandomUtils.generateRandomInt(0, 1) * hitSound.right(); + FastNMS.INSTANCE.method$LevelAccessor$playSound(args[0], null, blockPos, sound, CoreReflections.instance$SoundSource$BLOCKS, hitSound.left().volume().get(), pitch); } public static class Factory implements BlockBehaviorFactory { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - SoundData hitSound = SoundData.create(ResourceConfigUtils.requireNonNullOrThrow(arguments.get("hit-sound"), "warning.config.block.behavior.chime.missing_hit_sound"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); - Map randomPitch = ResourceConfigUtils.getAsMapOrNull(arguments.get("random-pitch"), "random-pitch"); - boolean enableRandomPitch = false; - float randomMultiplier = 1f; - if (randomPitch != null) { - enableRandomPitch = true; - randomMultiplier = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("multiplier", 1f), "multiplier"); - } - return new ChimeBlockBehavior(block, hitSound, enableRandomPitch, randomMultiplier); + List> hitSounds = ResourceConfigUtils.parseConfigAsList(arguments.get("hit-sounds"), map -> { + SoundData hitSound = SoundData.create(ResourceConfigUtils.requireNonNullOrThrow(arguments.get("sound"), "warning.config.block.behavior.chime.missing_hit_sound"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); + float randomMultiplier = ResourceConfigUtils.getAsFloat(arguments.get("random-pitch-multiplier"), "random-pitch-multiplier"); + return Pair.of(hitSound, randomMultiplier); + }); + return new ChimeBlockBehavior(block, hitSounds); } } } diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 789f9768a..7abfca063 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -17,7 +17,30 @@ items: parent: minecraft:block/custom/palm_log behavior: type: block_item - block: default:palm_log + block: + behavior: + type: strippable_block + stripped: default:stripped_palm_log + loot: + template: default:loot_table/self + settings: + template: default:settings/wood + states: + template: default:block_state/pillar + arguments: + base_block: note_block + texture_top_path: minecraft:block/custom/palm_log_top + texture_side_path: minecraft:block/custom/palm_log + model_vertical_path: minecraft:block/custom/palm_log + model_horizontal_path: minecraft:block/custom/palm_log_horizontal + vanilla_id: + type: self_increase_int + from: 0 + to: 2 + internal_id: + type: self_increase_int + from: 0 + to: 2 default:stripped_palm_log: material: nether_brick custom-model-data: 1001 @@ -36,7 +59,27 @@ items: parent: minecraft:block/custom/stripped_palm_log behavior: type: block_item - block: default:stripped_palm_log + block: + loot: + template: default:loot_table/self + settings: + template: default:settings/wood + states: + template: default:block_state/pillar + arguments: + base_block: note_block + texture_top_path: minecraft:block/custom/stripped_palm_log_top + texture_side_path: minecraft:block/custom/stripped_palm_log + model_vertical_path: minecraft:block/custom/stripped_palm_log + model_horizontal_path: minecraft:block/custom/stripped_palm_log_horizontal + vanilla_id: + type: self_increase_int + from: 3 + to: 5 + internal_id: + type: self_increase_int + from: 3 + to: 5 default:palm_wood: material: nether_brick custom-model-data: 1002 @@ -55,7 +98,30 @@ items: parent: minecraft:block/custom/palm_wood behavior: type: block_item - block: default:palm_wood + block: + behavior: + type: strippable_block + stripped: default:stripped_palm_wood + loot: + template: default:loot_table/self + settings: + template: default:settings/wood + states: + template: default:block_state/pillar + arguments: + base_block: note_block + texture_top_path: minecraft:block/custom/palm_log + texture_side_path: minecraft:block/custom/palm_log + model_vertical_path: minecraft:block/custom/palm_wood + model_horizontal_path: minecraft:block/custom/palm_wood_horizontal + vanilla_id: + type: self_increase_int + from: 6 + to: 8 + internal_id: + type: self_increase_int + from: 6 + to: 8 default:stripped_palm_wood: material: nether_brick custom-model-data: 1003 @@ -74,7 +140,27 @@ items: parent: minecraft:block/custom/stripped_palm_wood behavior: type: block_item - block: default:stripped_palm_wood + block: + loot: + template: default:loot_table/self + settings: + template: default:settings/wood + states: + template: default:block_state/pillar + arguments: + base_block: note_block + texture_top_path: minecraft:block/custom/stripped_palm_log + texture_side_path: minecraft:block/custom/stripped_palm_log + model_vertical_path: minecraft:block/custom/stripped_palm_wood + model_horizontal_path: minecraft:block/custom/stripped_palm_wood_horizontal + vanilla_id: + type: self_increase_int + from: 9 + to: 11 + internal_id: + type: self_increase_int + from: 9 + to: 11 default:palm_planks: material: nether_brick custom-model-data: 1004 @@ -92,7 +178,18 @@ items: parent: minecraft:block/custom/palm_planks behavior: type: block_item - block: default:palm_planks + block: + settings: + template: default:settings/planks + loot: + template: default:loot_table/self + state: + model: + template: default:model/simplified_cube_all + arguments: + path: minecraft:block/custom/palm_planks + id: 12 + state: note_block:12 default:palm_sapling: material: nether_brick custom-model-data: 1005 @@ -107,7 +204,42 @@ items: texture: minecraft:block/custom/palm_sapling behavior: type: block_item - block: default:palm_sapling + block: + settings: + template: default:settings/sapling + behaviors: + - type: bush_block + bottom-block-tags: + - minecraft:dirt + - minecraft:farmland + - minecraft:sand + - type: sapling_block + feature: minecraft:fancy_oak + bone-meal-success-chance: 0.45 + loot: + template: default:loot_table/self + states: + properties: + stage: + type: int + default-value: 0 + range: 0~1 + appearances: + default: + state: oak_sapling:0 + model: + path: minecraft:block/custom/palm_sapling + generation: + parent: minecraft:block/cross + textures: + cross: minecraft:block/custom/palm_sapling + variants: + stage=0: + appearance: default + id: 0 + stage=1: + appearance: default + id: 1 default:palm_leaves: material: oak_leaves custom-model-data: 1000 @@ -115,9 +247,9 @@ items: item-name: components: minecraft:block_state: - distance: "1" - persistent: "false" - waterlogged: "false" + distance: '1' + persistent: 'false' + waterlogged: 'false' model: type: minecraft:model path: minecraft:item/custom/palm_leaves @@ -128,7 +260,27 @@ items: value: -12012264 behavior: type: block_item - block: default:palm_leaves + block: + behavior: + type: leaves_block + loot: + template: default:loot_table/leaves + arguments: + leaves: default:palm_leaves + sapling: default:palm_sapling + settings: + template: default:settings/leaves + states: + template: default:block_state/leaves + arguments: + default_state: oak_leaves[distance=1,persistent=false,waterlogged=false] + waterlogged_state: oak_leaves[distance=1,persistent=false,waterlogged=true] + model_path: minecraft:block/custom/palm_leaves + texture_path: minecraft:block/custom/palm_leaves + internal_id: + type: self_increase_int + from: 0 + to: 27 default:palm_trapdoor: material: nether_brick custom-model-data: 1006 @@ -143,7 +295,47 @@ items: parent: minecraft:block/custom/palm_trapdoor_bottom behavior: type: block_item - block: default:palm_trapdoor + block: + behavior: + type: trapdoor_block + can-open-with-hand: true + can-open-by-wind-charge: true + sounds: + open: minecraft:block.wooden_trapdoor.open + close: minecraft:block.wooden_trapdoor.close + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + overrides: + map-color: 2 + instrument: bass + hardness: 3.0 + resistance: 3.0 + burnable: true + tags: + - minecraft:mineable/axe + - minecraft:trapdoors + states: + template: default:block_state/trapdoor + arguments: + base_block: acacia_trapdoor + model_bottom_path: minecraft:block/custom/palm_trapdoor_bottom + model_bottom_generation: + parent: minecraft:block/template_orientable_trapdoor_bottom + textures: + texture: minecraft:block/custom/palm_trapdoor + model_open_path: minecraft:block/custom/palm_trapdoor_open + model_open_generation: + parent: minecraft:block/template_orientable_trapdoor_open + textures: + texture: minecraft:block/custom/palm_trapdoor + model_top_path: minecraft:block/custom/palm_trapdoor_top + model_top_generation: + parent: minecraft:block/template_orientable_trapdoor_top + textures: + texture: minecraft:block/custom/palm_trapdoor default:palm_door: material: nether_brick custom-model-data: 1007 @@ -157,7 +349,68 @@ items: path: minecraft:item/custom/palm_door behavior: type: double_high_block_item - block: default:palm_door + block: + behavior: + type: door_block + can-open-with-hand: true + can-open-by-wind-charge: true + sounds: + open: minecraft:block.wooden_door.open + close: minecraft:block.wooden_door.close + loot: + template: default:loot_table/door + settings: + template: + - default:sound/wood + overrides: + push-reaction: destroy + map-color: 2 + instrument: bass + hardness: 3.0 + resistance: 3.0 + burnable: true + tags: + - minecraft:wooden_doors + - minecraft:doors + - minecraft:mineable/axe + states: + template: default:block_state/door + arguments: + base_block: oak_door + model_top_left_path: minecraft:block/custom/palm_door_top_left + model_top_left_generation: + parent: minecraft:block/door_top_left + textures: &textures + bottom: minecraft:block/custom/palm_door_bottom + top: minecraft:block/custom/palm_door_top + model_top_right_path: minecraft:block/custom/palm_door_top_right + model_top_right_generation: + parent: minecraft:block/door_top_right + textures: *textures + model_top_left_open_path: minecraft:block/custom/palm_door_top_left_open + model_top_left_open_generation: + parent: minecraft:block/door_top_left_open + textures: *textures + model_top_right_open_path: minecraft:block/custom/palm_door_top_right_open + model_top_right_open_generation: + parent: minecraft:block/door_top_right_open + textures: *textures + model_bottom_left_path: minecraft:block/custom/palm_door_bottom_left + model_bottom_left_generation: + parent: minecraft:block/door_bottom_left + textures: *textures + model_bottom_right_path: minecraft:block/custom/palm_door_bottom_right + model_bottom_right_generation: + parent: minecraft:block/door_bottom_right + textures: *textures + model_bottom_left_open_path: minecraft:block/custom/palm_door_bottom_left_open + model_bottom_left_open_generation: + parent: minecraft:block/door_bottom_left_open + textures: *textures + model_bottom_right_open_path: minecraft:block/custom/palm_door_bottom_right_open + model_bottom_right_open_generation: + parent: minecraft:block/door_bottom_right_open + textures: *textures default:palm_fence_gate: material: nether_brick custom-model-data: 1008 @@ -172,7 +425,49 @@ items: parent: minecraft:block/custom/palm_fence_gate behavior: type: block_item - block: default:palm_fence_gate + block: + behaviors: + type: fence_gate_block + can-open-with-hand: true + can-open-by-wind-charge: true + sounds: + open: minecraft:block.fence_gate.open + close: minecraft:block.fence_gate.close + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + - default:hardness/planks + overrides: + map-color: 2 + instrument: bass + burnable: true + tags: + - minecraft:fence_gates + - minecraft:mineable/axe + - minecraft:unstable_bottom_center + states: + template: default:block_state/fence_gate + arguments: + base_block: oak_fence_gate + model_fence_gate_path: minecraft:block/custom/palm_fence_gate + model_fence_gate_generation: + parent: minecraft:block/template_fence_gate + textures: &textures + texture: minecraft:block/custom/palm_planks + model_fence_gate_open_path: minecraft:block/custom/palm_fence_gate_open + model_fence_gate_open_generation: + parent: minecraft:block/template_fence_gate_open + textures: *textures + model_fence_gate_wall_path: minecraft:block/custom/palm_fence_gate_wall + model_fence_gate_wall_generation: + parent: minecraft:block/template_fence_gate_wall + textures: *textures + model_fence_gate_wall_open_path: minecraft:block/custom/palm_fence_gate_wall_open + model_fence_gate_wall_open_generation: + parent: minecraft:block/template_fence_gate_wall_open + textures: *textures default:palm_slab: material: nether_brick custom-model-data: 1009 @@ -187,7 +482,39 @@ items: parent: minecraft:block/custom/palm_slab behavior: type: block_item - block: default:palm_slab + block: + behaviors: + type: slab_block + loot: + template: default:loot_table/slab + settings: + template: + - default:sound/wood + - default:burn_data/planks + - default:hardness/planks + overrides: + map-color: 2 + instrument: bass + tags: + - minecraft:wooden_slabs + - minecraft:slabs + - minecraft:mineable/axe + states: + template: default:block_state/slab + arguments: + base_block: petrified_oak_slab + model_bottom_path: minecraft:block/custom/palm_slab + model_bottom_generation: + parent: minecraft:block/slab + textures: &textures + bottom: minecraft:block/custom/palm_planks + side: minecraft:block/custom/palm_planks + top: minecraft:block/custom/palm_planks + model_top_path: minecraft:block/custom/palm_slab_top + model_top_generation: + parent: minecraft:block/slab_top + textures: *textures + model_double_path: minecraft:block/custom/palm_planks default:palm_stairs: material: nether_brick custom-model-data: 1013 @@ -202,7 +529,42 @@ items: fuel-time: 300 behavior: type: block_item - block: default:palm_stairs + block: + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + - default:hardness/planks + - default:burn_data/planks + overrides: + map-color: 2 + instrument: bass + tags: + - minecraft:mineable/axe + - minecraft:stairs + - minecraft:wooden_stairs + behavior: + type: stairs_block + states: + template: default:block_state/stairs + arguments: + base_block: cut_copper_stairs + model_stairs_inner_path: minecraft:block/custom/palm_stairs_inner + model_stairs_inner_generation: + parent: minecraft:block/inner_stairs + textures: &textures + bottom: &block_texture minecraft:block/custom/palm_planks + side: *block_texture + top: *block_texture + model_stairs_outer_path: minecraft:block/custom/palm_stairs_outer + model_stairs_outer_generation: + parent: minecraft:block/outer_stairs + textures: *textures + model_stairs_path: minecraft:block/custom/palm_stairs + model_stairs_generation: + parent: minecraft:block/stairs + textures: *textures default:palm_pressure_plate: material: nether_brick custom-model-data: 1014 @@ -217,44 +579,49 @@ items: fuel-time: 300 behavior: type: block_item - block: default:palm_pressure_plate - default:palm_button: - material: nether_brick - custom-model-data: 1015 - model: - type: minecraft:model - path: minecraft:item/custom/palm_button - generation: - parent: minecraft:block/button_inventory - textures: - texture: minecraft:block/custom/palm_planks - data: - item-name: - settings: - fuel-time: 100 - behavior: - type: block_item - block: default:palm_button - default:palm_button_pressed: - material: nether_brick - custom-model-data: 1016 - model: - type: minecraft:model - path: minecraft:block/custom/palm_button_pressed - generation: - parent: minecraft:block/button_pressed - textures: - texture: minecraft:block/custom/palm_planks - default:palm_button_not_pressed: - material: nether_brick - custom-model-data: 1017 - model: - type: minecraft:model - path: minecraft:block/custom/palm_button_not_pressed - generation: - parent: minecraft:block/button - textures: - texture: minecraft:block/custom/palm_planks + block: + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + - default:hardness/planks + overrides: + burnable: true + push-reaction: destroy + map-color: 2 + instrument: bass + tags: + - minecraft:mineable/axe + - minecraft:wall_post_override + - minecraft:wooden_pressure_plates + - minecraft:pressure_plates + behaviors: + type: pressure_plate_block + sensitivity: all + pressed-time: 20 + sounds: + on: minecraft:block.wooden_pressure_plate.click_on + off: minecraft:block.wooden_pressure_plate.click_off + states: + template: default:block_state/pressure_plate + arguments: + normal_state: light_weighted_pressure_plate:0 + powered_state: light_weighted_pressure_plate:1 + normal_id: 0 + powered_id: 1 + model_normal_path: minecraft:block/custom/palm_pressure_plate + model_normal_generation: + parent: minecraft:block/pressure_plate_up + textures: + texture: minecraft:block/custom/palm_planks + model_powered_path: minecraft:block/custom/palm_pressure_plate_down + model_powered_generation: + parent: minecraft:block/pressure_plate_down + textures: + texture: minecraft:block/custom/palm_planks + +items#palm_fence: default:palm_fence: material: nether_brick custom-model-data: 1018 @@ -291,468 +658,7 @@ items: textures: texture: minecraft:block/custom/palm_planks -blocks: - default:palm_log: - behavior: - type: strippable_block - stripped: default:stripped_palm_log - loot: - template: default:loot_table/self - settings: - template: default:settings/wood - overrides: - map-color: 2 - states: - template: default:block_state/pillar - arguments: - base_block: note_block - texture_top_path: minecraft:block/custom/palm_log_top - texture_side_path: minecraft:block/custom/palm_log - model_vertical_path: minecraft:block/custom/palm_log - model_horizontal_path: minecraft:block/custom/palm_log_horizontal - vanilla_id: - type: self_increase_int - from: 0 - to: 2 - internal_id: - type: self_increase_int - from: 0 - to: 2 - default:stripped_palm_log: - loot: - template: default:loot_table/self - settings: - template: default:settings/wood - overrides: - map-color: 2 - states: - template: default:block_state/pillar - arguments: - base_block: note_block - texture_top_path: minecraft:block/custom/stripped_palm_log_top - texture_side_path: minecraft:block/custom/stripped_palm_log - model_vertical_path: minecraft:block/custom/stripped_palm_log - model_horizontal_path: minecraft:block/custom/stripped_palm_log_horizontal - vanilla_id: - type: self_increase_int - from: 3 - to: 5 - internal_id: - type: self_increase_int - from: 3 - to: 5 - default:palm_wood: - behavior: - type: strippable_block - stripped: default:stripped_palm_wood - loot: - template: default:loot_table/self - settings: - template: default:settings/wood - overrides: - map-color: 2 - states: - template: default:block_state/pillar - arguments: - base_block: note_block - texture_top_path: minecraft:block/custom/palm_log - texture_side_path: minecraft:block/custom/palm_log - model_vertical_path: minecraft:block/custom/palm_wood - model_horizontal_path: minecraft:block/custom/palm_wood_horizontal - vanilla_id: - type: self_increase_int - from: 6 - to: 8 - internal_id: - type: self_increase_int - from: 6 - to: 8 - default:stripped_palm_wood: - loot: - template: default:loot_table/self - settings: - template: default:settings/wood - overrides: - map-color: 2 - states: - template: default:block_state/pillar - arguments: - base_block: note_block - texture_top_path: minecraft:block/custom/stripped_palm_log - texture_side_path: minecraft:block/custom/stripped_palm_log - model_vertical_path: minecraft:block/custom/stripped_palm_wood - model_horizontal_path: minecraft:block/custom/stripped_palm_wood_horizontal - vanilla_id: - type: self_increase_int - from: 9 - to: 11 - internal_id: - type: self_increase_int - from: 9 - to: 11 - default:palm_planks: - settings: - template: default:settings/planks - overrides: - map-color: 2 - loot: - template: default:loot_table/self - state: - model: - template: default:model/simplified_cube_all - arguments: - path: minecraft:block/custom/palm_planks - id: 12 - state: note_block:12 - default:palm_sapling: - settings: - template: default:settings/sapling - behaviors: - - type: bush_block - bottom-block-tags: - - minecraft:dirt - - minecraft:farmland - - minecraft:sand - - type: sapling_block - feature: minecraft:fancy_oak - bone-meal-success-chance: 0.45 - loot: - template: default:loot_table/self - states: - properties: - stage: - type: int - default-value: 0 - range: 0~1 - appearances: - default: - state: oak_sapling:0 - model: - path: minecraft:block/custom/palm_sapling - generation: - parent: minecraft:block/cross - textures: - cross: minecraft:block/custom/palm_sapling - variants: - stage=0: - appearance: default - id: 0 - stage=1: - appearance: default - id: 1 - default:palm_leaves: - behavior: - type: leaves_block - loot: - template: default:loot_table/leaves - arguments: - leaves: default:palm_leaves - sapling: default:palm_sapling - settings: - template: default:settings/leaves - overrides: - map-color: 19 - states: - template: default:block_state/leaves - arguments: - default_state: oak_leaves[distance=1,persistent=false,waterlogged=false] - waterlogged_state: oak_leaves[distance=1,persistent=false,waterlogged=true] - model_path: minecraft:block/custom/palm_leaves - texture_path: minecraft:block/custom/palm_leaves - internal_id: - type: self_increase_int - from: 0 - to: 27 - default:palm_trapdoor: - behavior: - type: trapdoor_block - can-open-with-hand: true - can-open-by-wind-charge: true - sounds: - open: minecraft:block.wooden_trapdoor.open - close: minecraft:block.wooden_trapdoor.close - loot: - template: default:loot_table/self - settings: - template: - - default:sound/wood - overrides: - map-color: 2 - instrument: bass - hardness: 3.0 - resistance: 3.0 - burnable: true - tags: - - minecraft:mineable/axe - - minecraft:trapdoors - states: - template: default:block_state/trapdoor - arguments: - base_block: acacia_trapdoor - model_bottom_path: minecraft:block/custom/palm_trapdoor_bottom - model_bottom_generation: - parent: minecraft:block/template_orientable_trapdoor_bottom - textures: - texture: minecraft:block/custom/palm_trapdoor - model_open_path: minecraft:block/custom/palm_trapdoor_open - model_open_generation: - parent: minecraft:block/template_orientable_trapdoor_open - textures: - texture: minecraft:block/custom/palm_trapdoor - model_top_path: minecraft:block/custom/palm_trapdoor_top - model_top_generation: - parent: minecraft:block/template_orientable_trapdoor_top - textures: - texture: minecraft:block/custom/palm_trapdoor - default:palm_door: - behavior: - type: door_block - can-open-with-hand: true - can-open-by-wind-charge: true - sounds: - open: minecraft:block.wooden_door.open - close: minecraft:block.wooden_door.close - loot: - template: default:loot_table/door - settings: - template: - - default:sound/wood - overrides: - push-reaction: destroy - map-color: 2 - instrument: bass - hardness: 3.0 - resistance: 3.0 - burnable: true - tags: - - minecraft:wooden_doors - - minecraft:doors - - minecraft:mineable/axe - states: - template: default:block_state/door - arguments: - base_block: oak_door - model_top_left_path: minecraft:block/custom/palm_door_top_left - model_top_left_generation: - parent: minecraft:block/door_top_left - textures: &textures - bottom: minecraft:block/custom/palm_door_bottom - top: minecraft:block/custom/palm_door_top - model_top_right_path: minecraft:block/custom/palm_door_top_right - model_top_right_generation: - parent: minecraft:block/door_top_right - textures: *textures - model_top_left_open_path: minecraft:block/custom/palm_door_top_left_open - model_top_left_open_generation: - parent: minecraft:block/door_top_left_open - textures: *textures - model_top_right_open_path: minecraft:block/custom/palm_door_top_right_open - model_top_right_open_generation: - parent: minecraft:block/door_top_right_open - textures: *textures - model_bottom_left_path: minecraft:block/custom/palm_door_bottom_left - model_bottom_left_generation: - parent: minecraft:block/door_bottom_left - textures: *textures - model_bottom_right_path: minecraft:block/custom/palm_door_bottom_right - model_bottom_right_generation: - parent: minecraft:block/door_bottom_right - textures: *textures - model_bottom_left_open_path: minecraft:block/custom/palm_door_bottom_left_open - model_bottom_left_open_generation: - parent: minecraft:block/door_bottom_left_open - textures: *textures - model_bottom_right_open_path: minecraft:block/custom/palm_door_bottom_right_open - model_bottom_right_open_generation: - parent: minecraft:block/door_bottom_right_open - textures: *textures - default:palm_fence_gate: - behaviors: - type: fence_gate_block - can-open-with-hand: true - can-open-by-wind-charge: true - sounds: - open: minecraft:block.fence_gate.open - close: minecraft:block.fence_gate.close - loot: - template: default:loot_table/self - settings: - template: - - default:sound/wood - - default:hardness/planks - overrides: - map-color: 2 - instrument: bass - burnable: true - tags: - - minecraft:fence_gates - - minecraft:mineable/axe - - minecraft:unstable_bottom_center - states: - template: default:block_state/fence_gate - arguments: - base_block: oak_fence_gate - model_fence_gate_path: minecraft:block/custom/palm_fence_gate - model_fence_gate_generation: - parent: minecraft:block/template_fence_gate - textures: &textures - texture: minecraft:block/custom/palm_planks - model_fence_gate_open_path: minecraft:block/custom/palm_fence_gate_open - model_fence_gate_open_generation: - parent: minecraft:block/template_fence_gate_open - textures: *textures - model_fence_gate_wall_path: minecraft:block/custom/palm_fence_gate_wall - model_fence_gate_wall_generation: - parent: minecraft:block/template_fence_gate_wall - textures: *textures - model_fence_gate_wall_open_path: minecraft:block/custom/palm_fence_gate_wall_open - model_fence_gate_wall_open_generation: - parent: minecraft:block/template_fence_gate_wall_open - textures: *textures - default:palm_slab: - behaviors: - type: slab_block - loot: - template: default:loot_table/slab - settings: - template: - - default:sound/wood - - default:burn_data/planks - - default:hardness/planks - overrides: - map-color: 2 - instrument: bass - tags: - - minecraft:wooden_slabs - - minecraft:slabs - - minecraft:mineable/axe - states: - template: default:block_state/slab - arguments: - base_block: petrified_oak_slab - model_bottom_path: minecraft:block/custom/palm_slab - model_bottom_generation: - parent: minecraft:block/slab - textures: &textures - bottom: minecraft:block/custom/palm_planks - side: minecraft:block/custom/palm_planks - top: minecraft:block/custom/palm_planks - model_top_path: minecraft:block/custom/palm_slab_top - model_top_generation: - parent: minecraft:block/slab_top - textures: *textures - model_double_path: minecraft:block/custom/palm_planks - default:palm_stairs: - loot: - template: default:loot_table/self - settings: - template: - - default:sound/wood - - default:hardness/planks - - default:burn_data/planks - overrides: - map-color: 2 - instrument: bass - tags: - - minecraft:mineable/axe - - minecraft:stairs - - minecraft:wooden_stairs - behavior: - type: stairs_block - states: - template: default:block_state/stairs - arguments: - base_block: cut_copper_stairs - model_stairs_inner_path: minecraft:block/custom/palm_stairs_inner - model_stairs_inner_generation: - parent: minecraft:block/inner_stairs - textures: &textures - bottom: &block_texture minecraft:block/custom/palm_planks - side: *block_texture - top: *block_texture - model_stairs_outer_path: minecraft:block/custom/palm_stairs_outer - model_stairs_outer_generation: - parent: minecraft:block/outer_stairs - textures: *textures - model_stairs_path: minecraft:block/custom/palm_stairs - model_stairs_generation: - parent: minecraft:block/stairs - textures: *textures - default:palm_pressure_plate: - loot: - template: default:loot_table/self - settings: - template: - - default:sound/wood - - default:hardness/planks - overrides: - burnable: true - push-reaction: destroy - map-color: 2 - instrument: bass - tags: - - minecraft:mineable/axe - - minecraft:wall_post_override - - minecraft:wooden_pressure_plates - - minecraft:pressure_plates - behaviors: - type: pressure_plate_block - sensitivity: all - pressed-time: 20 - sounds: - on: minecraft:block.wooden_pressure_plate.click_on - off: minecraft:block.wooden_pressure_plate.click_off - states: - template: default:block_state/pressure_plate - arguments: - normal_state: light_weighted_pressure_plate:0 - powered_state: light_weighted_pressure_plate:1 - normal_id: 0 - powered_id: 1 - model_normal_path: minecraft:block/custom/palm_pressure_plate - model_normal_generation: - parent: minecraft:block/pressure_plate_up - textures: - texture: minecraft:block/custom/palm_planks - model_powered_path: minecraft:block/custom/palm_pressure_plate_down - model_powered_generation: - parent: minecraft:block/pressure_plate_down - textures: - texture: minecraft:block/custom/palm_planks - default:palm_button: - loot: - template: default:loot_table/self - settings: - template: - - default:sound/wood - - default:hardness/button - overrides: - burnable: true - push-reaction: destroy - map-color: 2 - instrument: harp - tags: - - minecraft:buttons - - minecraft:mineable/axe - - minecraft:wooden_buttons - behaviors: - - type: face_attached_horizontal_directional_block - - type: button_block - ticks-to-stay-pressed: 30 - can-button-be-activated-by-arrows: true - sounds: - on: minecraft:block.wooden_button.click_on - off: minecraft:block.wooden_button.click_off - states: - template: default:block_state/button - arguments: - base_block: birch_button - pressed_item: default:palm_button_pressed - not_pressed_item: default:palm_button_not_pressed - internal_id: - type: self_increase_int - from: 0 - to: 23 +blocks#palm_fence: default:palm_fence: loot: template: default:loot_table/self diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index b8ad2e75d..71d6e9e30 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -54,10 +54,6 @@ i18n: item.hami_melon_seeds: Hami Melon Seeds item.palm_button: Palm Button item.palm_fence: Palm Fence - item.infected_palm_log: Infected Palm Log - item.small_mushroom: Small Mushroom - item.medium_mushroom: Medium Mushroom - item.large_mushroom: Large Mushroom category.default.name: Default Assets category.default.lore: Contains the default configuration of CraftEngine category.palm_tree: Palm Tree @@ -121,10 +117,6 @@ i18n: item.hami_melon_seeds: 哈密瓜种子 item.palm_button: 棕榈木按钮 item.palm_fence: 棕榈木栅栏 - item.infected_palm_log: 菌蚀棕榈原木 - item.small_mushroom: 小型蘑菇 - item.medium_mushroom: 中型蘑菇 - item.large_mushroom: 大型蘑菇 category.default.name: 默认资产 category.default.lore: 包含了CraftEngine的默认配置 category.palm_tree: 棕榈树 @@ -172,10 +164,6 @@ lang: block_name:default:default:attached_hami_melon_stem: Hami Melon Stem block_name:default:palm_button: Palm Button block_name:default:palm_fence: Palm Fence - block_name:default:infected_palm_log: Infected Palm Log - block_name:default:small_mushroom: Small Mushroom - block_name:default:medium_mushroom: Medium Mushroom - block_name:default:large_mushroom: Large Mushroom zh_cn: block_name:default:chinese_lantern: 灯笼 block_name:default:netherite_anvil: 下界合金砧 @@ -211,7 +199,3 @@ lang: block_name:default:default:attached_hami_melon_stem: 哈密瓜茎 block_name:default:palm_button: 棕榈木按钮 block_name:default:palm_fence: 棕榈木栅栏 - block_name:default:infected_palm_log: 菌蚀棕榈原木 - block_name:default:small_mushroom: 小型蘑菇 - block_name:default:medium_mushroom: 中型蘑菇 - block_name:default:large_mushroom: 大型蘑菇 diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java index 8ff91b9a8..233ad526b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java @@ -171,6 +171,6 @@ public abstract class Property> { @Override public String toString() { - return MoreObjects.toStringHelper(this).add("name", this.name).add("clazz", this.clazz).add("values", this.possibleValues()).toString(); + return this.getClass().getSimpleName() + "{clazz=" + this.clazz + ", name='" + this.name + "', values=" + this.possibleValues() + '}'; } } From 154779cdf49fc4dd68728bf69335060036b46c9b Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 16:32:27 +0800 Subject: [PATCH 057/125] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AE=89=E5=85=A8?= =?UTF-8?q?=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/block/behavior/ChimeBlockBehavior.java | 1 + 1 file changed, 1 insertion(+) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java index b7897e76a..b61aa1243 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -27,6 +27,7 @@ public class ChimeBlockBehavior extends BukkitBlockBehavior { @Override public void onProjectileHit(Object thisBlock, Object[] args, Callable superMethod) { + if (hitSounds.isEmpty()) return; Pair hitSound = hitSounds.get(RandomUtils.generateRandomInt(0, hitSounds.size())); Object blockPos = FastNMS.INSTANCE.field$BlockHitResult$blockPos(args[2]); Object sound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(hitSound.left().id()), Optional.empty()); From a3e9e7491324dd427baa63d83afdd8fb5e85ea76 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 16:35:43 +0800 Subject: [PATCH 058/125] =?UTF-8?q?=E7=AE=80=E5=8C=96=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/ChimeBlockBehavior.java | 24 ++++++------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java index b61aa1243..fffedcef1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -7,44 +7,34 @@ import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.sound.SoundData; -import net.momirealms.craftengine.core.util.Pair; -import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; public class ChimeBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); - private final List> hitSounds; + private final SoundData hitSound; - public ChimeBlockBehavior(CustomBlock customBlock, List> hitSounds) { + public ChimeBlockBehavior(CustomBlock customBlock, SoundData hitSound) { super(customBlock); - this.hitSounds = hitSounds; + this.hitSound = hitSound; } @Override public void onProjectileHit(Object thisBlock, Object[] args, Callable superMethod) { - if (hitSounds.isEmpty()) return; - Pair hitSound = hitSounds.get(RandomUtils.generateRandomInt(0, hitSounds.size())); Object blockPos = FastNMS.INSTANCE.field$BlockHitResult$blockPos(args[2]); - Object sound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(hitSound.left().id()), Optional.empty()); - float pitch = hitSound.left().pitch().get() + RandomUtils.generateRandomInt(0, 1) * hitSound.right(); - FastNMS.INSTANCE.method$LevelAccessor$playSound(args[0], null, blockPos, sound, CoreReflections.instance$SoundSource$BLOCKS, hitSound.left().volume().get(), pitch); + Object sound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(hitSound.id()), Optional.empty()); + FastNMS.INSTANCE.method$LevelAccessor$playSound(args[0], null, blockPos, sound, CoreReflections.instance$SoundSource$BLOCKS, hitSound.volume().get(), hitSound.pitch().get()); } public static class Factory implements BlockBehaviorFactory { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - List> hitSounds = ResourceConfigUtils.parseConfigAsList(arguments.get("hit-sounds"), map -> { - SoundData hitSound = SoundData.create(ResourceConfigUtils.requireNonNullOrThrow(arguments.get("sound"), "warning.config.block.behavior.chime.missing_hit_sound"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); - float randomMultiplier = ResourceConfigUtils.getAsFloat(arguments.get("random-pitch-multiplier"), "random-pitch-multiplier"); - return Pair.of(hitSound, randomMultiplier); - }); - return new ChimeBlockBehavior(block, hitSounds); + SoundData hitSound = SoundData.create(ResourceConfigUtils.requireNonNullOrThrow(arguments.get("hit-sound"), "warning.config.block.behavior.chime.missing_hit_sound"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); + return new ChimeBlockBehavior(block, hitSound); } } } From 71915dce84bd913debba8d66a34205ad28da4cd4 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 16:43:20 +0800 Subject: [PATCH 059/125] =?UTF-8?q?=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/ChimeBlockBehavior.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java index fffedcef1..cadbbbcf7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -33,7 +33,12 @@ public class ChimeBlockBehavior extends BukkitBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - SoundData hitSound = SoundData.create(ResourceConfigUtils.requireNonNullOrThrow(arguments.get("hit-sound"), "warning.config.block.behavior.chime.missing_hit_sound"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); + SoundData hitSound = SoundData.create(ResourceConfigUtils.requireNonNullOrThrow( + Optional.ofNullable(arguments.get("sounds")) + .map(o -> ResourceConfigUtils.getAsMap(o , "hit").get("hit")) + .orElse(null), + "warning.config.block.behavior.chime.missing_hit_sound" + ), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); return new ChimeBlockBehavior(block, hitSound); } } From 80eebec58626b8f46e3026cb81a85adb28cb8857 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 16:52:34 +0800 Subject: [PATCH 060/125] =?UTF-8?q?=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/BuddingBlockBehavior.java | 8 ++-- .../block/behavior/ChimeBlockBehavior.java | 2 +- .../resources/default/configuration/i18n.yml | 4 +- .../default/configuration/templates.yml | 37 ------------------- .../src/main/resources/translations/en.yml | 2 +- .../src/main/resources/translations/zh_cn.yml | 2 +- 6 files changed, 9 insertions(+), 46 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BuddingBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BuddingBlockBehavior.java index a42367d2d..0fab2a5ca 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BuddingBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BuddingBlockBehavior.java @@ -20,10 +20,10 @@ import java.util.concurrent.Callable; public class BuddingBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); - private final int growthChance; + private final float growthChance; private final List blocks; - public BuddingBlockBehavior(CustomBlock customBlock, int growthChance, List blocks) { + public BuddingBlockBehavior(CustomBlock customBlock, float growthChance, List blocks) { super(customBlock); this.growthChance = growthChance; this.blocks = blocks; @@ -31,7 +31,7 @@ public class BuddingBlockBehavior extends BukkitBlockBehavior { @Override public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws Exception { - if (RandomUtils.generateRandomInt(0, this.growthChance) != 0) return; + if (RandomUtils.generateRandomFloat(0, 1) >= growthChance) return; Object nmsDirection = CoreReflections.instance$Direction$values[RandomUtils.generateRandomInt(0, 6)]; Direction direction = DirectionUtils.fromNMSDirection(nmsDirection); Object blockPos = FastNMS.INSTANCE.method$BlockPos$relative(args[2], nmsDirection); @@ -90,7 +90,7 @@ public class BuddingBlockBehavior extends BukkitBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { - int growthChance = ResourceConfigUtils.getAsInt(arguments.getOrDefault("growth-chance", 5), "growth-chance"); + float growthChance = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("growth-chance", 0.2), "growth-chance"); List blocks = new ObjectArrayList<>(); MiscUtils.getAsStringList(arguments.get("blocks")).forEach(s -> blocks.add(Key.of(s))); return new BuddingBlockBehavior(block, growthChance, blocks); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java index cadbbbcf7..e11eb1d3b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -37,7 +37,7 @@ public class ChimeBlockBehavior extends BukkitBlockBehavior { Optional.ofNullable(arguments.get("sounds")) .map(o -> ResourceConfigUtils.getAsMap(o , "hit").get("hit")) .orElse(null), - "warning.config.block.behavior.chime.missing_hit_sound" + "warning.config.block.behavior.chime.missing_sounds_hit" ), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); return new ChimeBlockBehavior(block, hitSound); } diff --git a/common-files/src/main/resources/resources/default/configuration/i18n.yml b/common-files/src/main/resources/resources/default/configuration/i18n.yml index 71d6e9e30..a0c7eea40 100644 --- a/common-files/src/main/resources/resources/default/configuration/i18n.yml +++ b/common-files/src/main/resources/resources/default/configuration/i18n.yml @@ -161,7 +161,7 @@ lang: block_name:default:amethyst_wall_torch: Amethyst Torch block_name:default:hami_melon: Hami Melon block_name:default:hami_melon_stem: Hami Melon Stem - block_name:default:default:attached_hami_melon_stem: Hami Melon Stem + block_name:default:attached_hami_melon_stem: Hami Melon Stem block_name:default:palm_button: Palm Button block_name:default:palm_fence: Palm Fence zh_cn: @@ -196,6 +196,6 @@ lang: block_name:default:amethyst_wall_torch: 紫水晶火把 block_name:default:hami_melon: 哈密瓜 block_name:default:hami_melon_stem: 哈密瓜茎 - block_name:default:default:attached_hami_melon_stem: 哈密瓜茎 + block_name:default:attached_hami_melon_stem: 哈密瓜茎 block_name:default:palm_button: 棕榈木按钮 block_name:default:palm_fence: 棕榈木栅栏 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 20392707e..fa284b068 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -3930,43 +3930,6 @@ templates#block_states: resistance: 1200.0 burnable: false fluid-state: water - default:block_state/mushroom: - properties: - facing: - type: horizontal_direction - appearances: - north: - state: ${base_block}[waterlogged=false,facing=north] - model: - path: ${model_path} - east: - state: ${base_block}[waterlogged=false,facing=east] - model: - path: ${model_path} - y: 90 - west: - state: ${base_block}[waterlogged=false,facing=west] - model: - path: ${model_path} - y: 270 - south: - state: ${base_block}[waterlogged=false,facing=south] - model: - path: ${model_path} - y: 180 - variants: - facing=north: - appearance: north - id: 0 - facing=east: - appearance: east - id: 1 - facing=west: - appearance: west - id: 2 - facing=south: - appearance: south - id: 3 # recipes templates#recipes: default:recipe/planks: diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 6c88ca4a0..33f9fde42 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -336,7 +336,7 @@ warning.config.block.behavior.stem.missing_attached_stem: "Issue found i warning.config.block.behavior.attached_stem.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'attached_stem_block' behavior." warning.config.block.behavior.attached_stem.missing_fruit: "Issue found in file - The block '' is missing the required 'fruit' argument for 'attached_stem_block' behavior." warning.config.block.behavior.attached_stem.missing_stem: "Issue found in file - The block '' is missing the required 'stem' argument for 'attached_stem_block' behavior." -warning.config.block.behavior.chime.missing_hit_sound: "Issue found in file - The block '' is missing the required 'hit-sound' argument for 'chime_block' behavior." +warning.config.block.behavior.chime.missing_sounds_hit: "Issue found in file - The block '' is missing the required 'sounds.hit' argument for 'chime_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.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." 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: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 4072ac068..0bc2572c9 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -330,7 +330,7 @@ warning.config.block.behavior.stem.missing_attached_stem: "在文件 在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'facing' 属性" warning.config.block.behavior.attached_stem.missing_fruit: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项" warning.config.block.behavior.attached_stem.missing_stem: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项" -warning.config.block.behavior.chime.missing_hit_sound: "在文件 发现问题 - 方块 '' 的 'chime_block' 行为缺少必需的 'hit-sound' 选项" +warning.config.block.behavior.chime.missing_sounds_hit: "在文件 发现问题 - 方块 '' 的 'chime_block' 行为缺少必需的 'sounds.hit' 选项" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" From 760c0bd560d76802a6e1ccf748f1bc91cf035332 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 17:02:36 +0800 Subject: [PATCH 061/125] =?UTF-8?q?=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/ChimeBlockBehavior.java | 9 +++++++-- common-files/src/main/resources/translations/en.yml | 2 +- common-files/src/main/resources/translations/zh_cn.yml | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java index e11eb1d3b..3ddc5b8df 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -10,8 +10,10 @@ import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.Callable; +import java.util.stream.Stream; public class ChimeBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); @@ -35,9 +37,12 @@ public class ChimeBlockBehavior extends BukkitBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { SoundData hitSound = SoundData.create(ResourceConfigUtils.requireNonNullOrThrow( Optional.ofNullable(arguments.get("sounds")) - .map(o -> ResourceConfigUtils.getAsMap(o , "hit").get("hit")) + .flatMap(sounds -> Stream.of("projectile-hit", "chime") + .map(type -> ResourceConfigUtils.getAsMap(sounds, type).get(type)) + .filter(Objects::nonNull) + .findFirst()) .orElse(null), - "warning.config.block.behavior.chime.missing_sounds_hit" + "warning.config.block.behavior.chime.missing_sounds_projectile_hit" ), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); return new ChimeBlockBehavior(block, hitSound); } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 33f9fde42..092ca02ce 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -336,7 +336,7 @@ warning.config.block.behavior.stem.missing_attached_stem: "Issue found i warning.config.block.behavior.attached_stem.missing_facing: "Issue found in file - The block '' is missing the required 'facing' property for 'attached_stem_block' behavior." warning.config.block.behavior.attached_stem.missing_fruit: "Issue found in file - The block '' is missing the required 'fruit' argument for 'attached_stem_block' behavior." warning.config.block.behavior.attached_stem.missing_stem: "Issue found in file - The block '' is missing the required 'stem' argument for 'attached_stem_block' behavior." -warning.config.block.behavior.chime.missing_sounds_hit: "Issue found in file - The block '' is missing the required 'sounds.hit' argument for 'chime_block' behavior." +warning.config.block.behavior.chime.missing_sounds_projectile_hit: "Issue found in file - The block '' is missing the required 'sounds.projectile-hit' argument for 'chime_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.conflict: "Issue found in file - Failed to generate model for '' as two or more configurations attempt to generate different json models with the same path: ''." 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: []" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 0bc2572c9..8b6fc7227 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -330,7 +330,7 @@ warning.config.block.behavior.stem.missing_attached_stem: "在文件 在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'facing' 属性" warning.config.block.behavior.attached_stem.missing_fruit: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'fruit' 选项" warning.config.block.behavior.attached_stem.missing_stem: "在文件 发现问题 - 方块 '' 的 'attached_stem_block' 行为缺少必需的 'stem' 选项" -warning.config.block.behavior.chime.missing_sounds_hit: "在文件 发现问题 - 方块 '' 的 'chime_block' 行为缺少必需的 'sounds.hit' 选项" +warning.config.block.behavior.chime.missing_sounds_projectile_hit: "在文件 发现问题 - 方块 '' 的 'chime_block' 行为缺少必需的 'sounds.projectile-hit' 选项" warning.config.model.generation.missing_parent: "在文件 发现问题 - 配置项 '' 的 'generation' 段落缺少必需的 'parent' 参数" warning.config.model.generation.conflict: "在文件 发现问题 - 无法为 '' 生成模型 存在多个配置尝试使用相同路径 '' 生成不同的 JSON 模型" warning.config.model.generation.invalid_display_position: "在文件 发现问题 - 配置项 '' 在 'generation.display' 区域使用了无效的 display 位置类型 ''. 可用展示类型: []" From d5da77f0764de5ef3ee875206fbdfd222d896133 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Wed, 24 Sep 2025 17:06:02 +0800 Subject: [PATCH 062/125] =?UTF-8?q?=E4=BF=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/behavior/ChimeBlockBehavior.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java index 3ddc5b8df..56e68b810 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -36,11 +36,8 @@ public class ChimeBlockBehavior extends BukkitBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { SoundData hitSound = SoundData.create(ResourceConfigUtils.requireNonNullOrThrow( - Optional.ofNullable(arguments.get("sounds")) - .flatMap(sounds -> Stream.of("projectile-hit", "chime") - .map(type -> ResourceConfigUtils.getAsMap(sounds, type).get(type)) - .filter(Objects::nonNull) - .findFirst()) + Optional.ofNullable(ResourceConfigUtils.getAsMap(arguments.get("sounds"), "sounds")) + .map(sounds -> ResourceConfigUtils.get(sounds, "projectile-hit", "chime")) .orElse(null), "warning.config.block.behavior.chime.missing_sounds_projectile_hit" ), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); From 28f30b1e5b84f15ca714189b81e57d7683e65373 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Wed, 24 Sep 2025 19:04:07 +0800 Subject: [PATCH 063/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/blocks/palm_tree.yml | 81 ++++++++++++++++++- .../default/configuration/categories.yml | 12 +-- 2 files changed, 83 insertions(+), 10 deletions(-) diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 7abfca063..82036eea1 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -621,7 +621,7 @@ items: textures: texture: minecraft:block/custom/palm_planks -items#palm_fence: +items#pfence: default:palm_fence: material: nether_brick custom-model-data: 1018 @@ -657,8 +657,7 @@ items#palm_fence: parent: minecraft:block/custom/fence_side textures: texture: minecraft:block/custom/palm_planks - -blocks#palm_fence: +blocks#fence: default:palm_fence: loot: template: default:loot_table/self @@ -695,6 +694,80 @@ blocks#palm_fence: from: 0 to: 31 +items#button: + default:palm_button: + material: nether_brick + custom-model-data: 1015 + model: + type: minecraft:model + path: minecraft:item/custom/palm_button + generation: + parent: minecraft:block/button_inventory + textures: + texture: minecraft:block/custom/palm_planks + data: + item-name: + settings: + fuel-time: 100 + behavior: + type: block_item + block: default:palm_button + default:palm_button_pressed: + material: nether_brick + custom-model-data: 1016 + model: + type: minecraft:model + path: minecraft:block/custom/palm_button_pressed + generation: + parent: minecraft:block/button_pressed + textures: + texture: minecraft:block/custom/palm_planks + default:palm_button_not_pressed: + material: nether_brick + custom-model-data: 1017 + model: + type: minecraft:model + path: minecraft:block/custom/palm_button_not_pressed + generation: + parent: minecraft:block/button + textures: + texture: minecraft:block/custom/palm_planks +blocks#button: + default:palm_button: + loot: + template: default:loot_table/self + settings: + template: + - default:sound/wood + - default:hardness/button + overrides: + burnable: true + push-reaction: destroy + map-color: 2 + instrument: harp + tags: + - minecraft:buttons + - minecraft:mineable/axe + - minecraft:wooden_buttons + behaviors: + - type: face_attached_horizontal_directional_block + - type: button_block + ticks-to-stay-pressed: 30 + can-button-be-activated-by-arrows: true + sounds: + on: minecraft:block.wooden_button.click_on + off: minecraft:block.wooden_button.click_off + states: + template: default:block_state/button + arguments: + base_block: birch_button + pressed_item: default:palm_button_pressed + not_pressed_item: default:palm_button_not_pressed + internal_id: + type: self_increase_int + from: 0 + to: 23 + recipes: default:palm_planks: template: default:recipe/planks @@ -787,4 +860,4 @@ recipes: B: minecraft:stick result: id: default:palm_fence - count: 1 + count: 1 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/categories.yml b/common-files/src/main/resources/resources/default/configuration/categories.yml index 2d911abe4..a1a9a71c8 100644 --- a/common-files/src/main/resources/resources/default/configuration/categories.yml +++ b/common-files/src/main/resources/resources/default/configuration/categories.yml @@ -17,18 +17,18 @@ categories: - default:palm_sapling - default:palm_leaves - default:palm_log - - default:stripped_palm_log - default:palm_wood + - default:stripped_palm_log - default:stripped_palm_wood - default:palm_planks - - default:palm_trapdoor - - default:palm_door - - default:palm_fence_gate - - default:palm_slab - default:palm_stairs + - default:palm_slab + - default:palm_fence + - default:palm_fence_gate + - default:palm_door + - default:palm_trapdoor - default:palm_pressure_plate - default:palm_button - - default:palm_fence default:topaz: name: <#FF8C00> hidden: true From ee6e0b83567f5fff27c225917e23a6f4a084a066 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Wed, 24 Sep 2025 19:04:19 +0800 Subject: [PATCH 064/125] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index e5de2af92..f078e28e6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.5 +project_version=0.0.63.6 config_version=46 lang_version=31 project_group=net.momirealms From f9448bfbffcbe555fa6f1df47d6dec550ddda0a3 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Wed, 24 Sep 2025 19:12:36 +0800 Subject: [PATCH 065/125] Update palm_tree.yml --- .../resources/default/configuration/blocks/palm_tree.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 82036eea1..7e5fcef3a 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -860,4 +860,4 @@ recipes: B: minecraft:stick result: id: default:palm_fence - count: 1 \ No newline at end of file + count: 3 \ No newline at end of file From e12273e60071014a39dcd1c98556e4fc8b9693a6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Fri, 26 Sep 2025 21:58:21 +0800 Subject: [PATCH 066/125] =?UTF-8?q?=E9=87=8D=E6=96=B0=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BukkitCompatibilityManager.java | 6 +- .../plugin/BukkitCraftEnginePlugin.java | 2 +- .../plugin/PaperCraftEngineBootstrap.java | 2 +- .../advancement/BukkitAdvancementManager.java | 3 +- .../bukkit/api/CraftEngineBlocks.java | 10 + .../bukkit/block/BlockEventListener.java | 5 +- .../bukkit/block/BukkitBlockManager.java | 706 +-- .../bukkit/block/BukkitBlockStateWrapper.java | 11 + .../bukkit/block/BukkitCustomBlock.java | 124 - .../block/behavior/BushBlockBehavior.java | 2 +- .../block/behavior/ChimeBlockBehavior.java | 2 - .../DirectionalAttachedBlockBehavior.java | 2 +- .../block/behavior/FallingBlockBehavior.java | 27 +- .../item/behavior/BlockItemBehavior.java | 4 +- .../behavior/DoubleHighBlockItemBehavior.java | 4 +- .../LiquidCollisionBlockItemBehavior.java | 4 +- .../item/behavior/WallBlockItemBehavior.java | 4 +- .../bukkit/loot/BukkitVanillaLootManager.java | 7 +- .../bukkit/plugin/BukkitCraftEngine.java | 10 +- .../DebugAppearanceStateUsageCommand.java | 94 +- .../feature/DebugRealStateUsageCommand.java | 76 +- .../plugin/injector/BlockGenerator.java | 26 + .../plugin/network/BukkitNetworkManager.java | 35 +- .../protocol/ClientBlockStateSizePacket.java | 1 - .../reflection/minecraft/CoreReflections.java | 9 +- .../plugin/user/BukkitServerPlayer.java | 2 +- .../bukkit/util/BlockStateUtils.java | 55 +- .../util/NoteBlockChainUpdateUtils.java | 3 +- .../bukkit/world/BukkitExistingBlock.java | 2 +- .../main/resources/additional-real-blocks.yml | 91 - common-files/src/main/resources/config.yml | 2 +- common-files/src/main/resources/mappings.yml | 4452 ----------------- .../configuration/blocks/amethyst_torch.yml | 8 - .../configuration/blocks/chessboard_block.yml | 5 - .../configuration/blocks/chinese_lantern.yml | 2 - .../configuration/blocks/copper_coil.yml | 3 - .../blocks/ender_pearl_flower.yml | 4 - .../configuration/blocks/fairy_flower.yml | 2 - .../configuration/blocks/flame_cane.yml | 7 - .../configuration/blocks/gunpowder_block.yml | 4 - .../configuration/blocks/hami_melon.yml | 16 - .../configuration/blocks/netherite_anvil.yml | 10 +- .../configuration/blocks/palm_tree.yml | 68 - .../default/configuration/blocks/pebble.yml | 4 - .../default/configuration/blocks/reed.yml | 2 - .../configuration/blocks/safe_block.yml | 9 - .../default/configuration/blocks/sofa.yml | 18 +- .../configuration/blocks/table_lamp.yml | 10 - .../configuration/blocks/topaz_ore.yml | 5 - .../default/configuration/furniture/bench.yml | 1 - .../configuration/furniture/flower_basket.yml | 4 - .../configuration/furniture/wooden_chair.yml | 1 - .../default/configuration/items/cap.yml | 1 - .../configuration/items/flame_elytra.yml | 1 - .../default/configuration/items/gui_head.yml | 4 - .../configuration/items/topaz_armor.yml | 1 - .../configuration/items/topaz_tool_weapon.yml | 10 - .../default/configuration/templates.yml | 341 +- .../resources/internal/configuration/gui.yml | 13 - .../internal/configuration/mappings.yml | 4451 ++++++++++++++++ .../src/main/resources/translations/de.yml | 1 - .../src/main/resources/translations/en.yml | 4 +- .../src/main/resources/translations/es.yml | 1 - .../src/main/resources/translations/ru_ru.yml | 1 - .../src/main/resources/translations/tr.yml | 1 - .../src/main/resources/translations/zh_cn.yml | 2 +- .../core/block/AbstractBlockManager.java | 262 +- .../core/block/AbstractCustomBlock.java | 18 +- .../craftengine/core/block/BlockManager.java | 13 +- .../core/block/BlockRegistryMirror.java | 8 +- .../craftengine/core/block/BlockSounds.java | 21 +- .../core/block/BlockStateAppearance.java | 7 +- .../core/block/BlockStateVariant.java | 10 +- .../core/block/BlockStateWrapper.java | 4 + .../core/block/DelegatingBlock.java | 2 + .../craftengine/core/block/EmptyBlock.java | 4 - .../core/block/InactiveCustomBlock.java | 4 - .../craftengine/core/block/PushReaction.java | 4 +- .../core/block/properties/Property.java | 1 - .../furniture/AbstractFurnitureManager.java | 6 +- .../core/font/AbstractFontManager.java | 5 +- .../core/item/AbstractItemManager.java | 5 +- .../item/recipe/AbstractRecipeManager.java | 3 +- .../core/pack/AbstractPackManager.java | 84 +- .../core/pack/LoadingSequence.java | 1 + .../craftengine/core/plugin/CraftEngine.java | 7 +- .../core/plugin/config/Config.java | 42 +- .../core/plugin/config/ConfigParser.java | 17 - .../plugin/config/IdObjectConfigParser.java | 13 + .../plugin/config/IdSectionConfigParser.java | 14 + .../plugin/config/SectionConfigParser.java | 13 + .../config/template/TemplateManagerImpl.java | 8 +- .../plugin/context/GlobalVariableManager.java | 8 +- .../gui/category/ItemBrowserManagerImpl.java | 3 +- .../plugin/locale/TranslationManager.java | 2 - .../plugin/locale/TranslationManagerImpl.java | 18 +- .../core/plugin/logger/Debugger.java | 1 + .../core/plugin/network/NetWorkUser.java | 1 + .../core/sound/AbstractSoundManager.java | 5 +- .../craftengine/core/sound/SoundData.java | 1 + .../craftengine/core/util/Instrument.java | 2 + 101 files changed, 5278 insertions(+), 6137 deletions(-) delete mode 100644 common-files/src/main/resources/additional-real-blocks.yml delete mode 100644 common-files/src/main/resources/mappings.yml create mode 100644 common-files/src/main/resources/resources/internal/configuration/mappings.yml create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/config/SectionConfigParser.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index c4ca0328e..f35396548 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 @@ -20,12 +20,14 @@ import net.momirealms.craftengine.bukkit.compatibility.worldedit.WorldEditBlockR import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.core.block.BlockManager; import net.momirealms.craftengine.core.entity.furniture.ExternalModel; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.loot.LootConditions; import net.momirealms.craftengine.core.plugin.compatibility.CompatibilityManager; import net.momirealms.craftengine.core.plugin.compatibility.LevelerProvider; import net.momirealms.craftengine.core.plugin.compatibility.ModelProvider; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.condition.AlwaysFalseCondition; import net.momirealms.craftengine.core.plugin.context.event.EventConditions; import net.momirealms.craftengine.core.util.Key; @@ -246,8 +248,8 @@ public class BukkitCompatibilityManager implements CompatibilityManager { private void initWorldEditHook() { WorldEditBlockRegister weBlockRegister = new WorldEditBlockRegister(BukkitBlockManager.instance(), false); try { - for (Key newBlockId : BukkitBlockManager.instance().blockRegisterOrder()) { - weBlockRegister.register(newBlockId); + for (int i = 0; i < Config.serverSideBlocks(); i++) { + weBlockRegister.register(BlockManager.createCustomBlockKey(i)); } } catch (Exception e) { this.plugin.logger().warn("Failed to initialize world edit hook", e); diff --git a/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEnginePlugin.java b/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEnginePlugin.java index 5f9871d85..cbd3aacbe 100644 --- a/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEnginePlugin.java +++ b/bukkit/loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEnginePlugin.java @@ -8,7 +8,7 @@ public class BukkitCraftEnginePlugin extends JavaPlugin { public BukkitCraftEnginePlugin() { this.plugin = new BukkitCraftEngine(this); this.plugin.applyDependencies(); - this.plugin.setUpConfig(); + this.plugin.setUpConfigAndLocale(); } @Override diff --git a/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEngineBootstrap.java b/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEngineBootstrap.java index 05364cd61..45eb0a35d 100644 --- a/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEngineBootstrap.java +++ b/bukkit/paper-loader/src/main/java/net/momirealms/craftengine/bukkit/plugin/PaperCraftEngineBootstrap.java @@ -55,7 +55,7 @@ public class PaperCraftEngineBootstrap implements PluginBootstrap { ); } this.plugin.applyDependencies(); - this.plugin.setUpConfig(); + this.plugin.setUpConfigAndLocale(); if (isDatapackDiscoveryAvailable()) { new ModernEventHandler(context, this.plugin).register(); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java index c037f46c3..1cbff1a44 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; @@ -105,7 +106,7 @@ public class BukkitAdvancementManager extends AbstractAdvancementManager { } } - public class AdvancementParser implements ConfigParser { + public class AdvancementParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"advancements", "advancement"}; @Override 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 3fb08edd3..d769ab88f 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 @@ -286,4 +286,14 @@ public final class CraftEngineBlocks { public static BlockData getBukkitBlockData(@NotNull ImmutableBlockState blockState) { return BlockStateUtils.fromBlockData(blockState.customBlockState().literalObject()); } + + /** + * Checks if the block state is a vanilla block state + * + * @param id state id + * @return is vanilla block or not + */ + public static boolean isVanillaBlockState(int id) { + return BukkitBlockManager.instance().isVanillaBlockState(id); + } } 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 1daab5e9d..7350e97b4 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 @@ -44,13 +44,11 @@ import java.util.Optional; public final class BlockEventListener implements Listener { private final BukkitCraftEngine plugin; - private final boolean enableNoteBlockCheck; private final BukkitBlockManager manager; - public BlockEventListener(BukkitCraftEngine plugin, BukkitBlockManager manager, boolean enableNoteBlockCheck) { + public BlockEventListener(BukkitCraftEngine plugin, BukkitBlockManager manager) { this.plugin = plugin; this.manager = manager; - this.enableNoteBlockCheck = enableNoteBlockCheck; } @EventHandler(ignoreCancelled = true) @@ -276,7 +274,6 @@ public final class BlockEventListener implements Listener { @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onBlockPhysics(BlockPhysicsEvent event) { - if (!this.enableNoteBlockCheck) return; // for vanilla blocks if (event.getChangedType() == Material.NOTE_BLOCK) { Block block = event.getBlock(); 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 7dfe46fa0..5fc635efe 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 @@ -1,16 +1,10 @@ package net.momirealms.craftengine.bukkit.block; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BlockGenerator; -import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; @@ -24,100 +18,69 @@ import net.momirealms.craftengine.bukkit.util.TagUtils; import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; import net.momirealms.craftengine.core.block.parser.BlockStateParser; -import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; +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.plugin.logger.Debugger; 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.sound.SoundData; -import net.momirealms.craftengine.core.sound.Sounds; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.block.data.BlockData; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.yaml.snakeyaml.LoaderOptions; -import org.yaml.snakeyaml.Yaml; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; public final class BukkitBlockManager extends AbstractBlockManager { + public static final Set CLIENT_SIDE_NOTE_BLOCKS = new HashSet<>(2048, 0.6f); + private static final Object ALWAYS_FALSE = FastNMS.INSTANCE.method$StatePredicate$always(false); + private static final Object ALWAYS_TRUE = FastNMS.INSTANCE.method$StatePredicate$always(true); private static BukkitBlockManager instance; private final BukkitCraftEngine plugin; - - // The total amount of blocks registered - private int customBlockCount; - private ImmutableBlockState[] stateId2ImmutableBlockStates; - // Minecraft objects - // Cached new blocks $ holders - private Map stateId2BlockHolder; - // This map is used to change the block states that are not necessarily needed into a certain block state - private Map blockAppearanceMapper; - // Record the amount of real blocks by block type - private Map registeredRealBlockSlots; - // A set of blocks that sounds have been removed - private Set affectedSoundBlocks; - private Map> affectedOpenableBlockSounds; - private Map soundMapper; - // A list to record the order of registration - private List blockRegisterOrder = new ObjectArrayList<>(); - // Event listeners + // 事件监听器 private BlockEventListener blockEventListener; - // cached tag packet + // 可燃烧的方块 + private Map igniteOdds; + private Map burnOdds; + // 自定义客户端侧原版方块标签 + private Map> clientBoundTags = Map.of(); + private Map> previousClientBoundTags = Map.of(); + // 缓存的原版方块tag包 private Object cachedUpdateTagsPacket; - - private final List> blocksToDeceive = new ArrayList<>(); + // 被移除声音的原版方块 + private final Set replacedBlockSounds = new HashSet<>(); + // 用于缓存string形式的方块状态到原版方块状态 + private final Map blockStateCache = new HashMap<>(1024); public BukkitBlockManager(BukkitCraftEngine plugin) { - super(plugin); - instance = this; + super(plugin, RegistryUtils.currentBlockRegistrySize(), Config.serverSideBlocks()); this.plugin = plugin; - this.initVanillaRegistry(); - this.loadMappingsAndAdditionalBlocks(); - this.registerBlocks(); + this.registerServerSideCustomBlocks(Config.serverSideBlocks()); this.registerEmptyBlock(); + instance = this; } @Override public void init() { this.initMirrorRegistry(); - this.deceiveBukkit(); - boolean enableNoteBlocks = this.blockAppearanceArranger.containsKey(BlockKeys.NOTE_BLOCK); - this.blockEventListener = new BlockEventListener(plugin, this, enableNoteBlocks); - if (enableNoteBlocks) { - this.recordVanillaNoteBlocks(); - } - this.stateId2ImmutableBlockStates = new ImmutableBlockState[this.customBlockCount]; - Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.INSTANCE.defaultState()); - this.resetPacketListeners(); - } - - @Override - public String stateRegistryIdToStateSNBT(int id) { - return BlockStateUtils.idToBlockState(id).toString(); + this.initFireBlock(); + this.initVanillaBlockSettings(); + this.deceiveBukkitRegistry(); + this.markVanillaNoteBlocks(); + this.blockEventListener = new BlockEventListener(plugin, this); + Arrays.fill(this.immutableBlockStates, EmptyBlock.INSTANCE.defaultState()); + this.plugin.networkManager().registerBlockStatePacketListeners(this.blockStateMappings); // 一定要预先初始化一次,预防id超出上限 } public static BukkitBlockManager instance() { return instance; } - public List blockRegisterOrder() { - return Collections.unmodifiableList(this.blockRegisterOrder); - } - @Override public void delayedInit() { Bukkit.getPluginManager().registerEvents(this.blockEventListener, this.plugin.javaPlugin()); @@ -126,9 +89,12 @@ public final class BukkitBlockManager extends AbstractBlockManager { @Override public void unload() { super.unload(); + Arrays.fill(this.blockStateMappings, -1); + this.previousClientBoundTags = this.clientBoundTags; + this.clientBoundTags = new HashMap<>(); if (EmptyBlock.STATE != null) - Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.STATE); - for (DelegatingBlock block : this.registeredBlocks.values()) { + Arrays.fill(this.immutableBlockStates, EmptyBlock.STATE); + for (DelegatingBlock block : this.customBlocks) { block.behaviorDelegate().bindValue(EmptyBlockBehavior.INSTANCE); block.shapeDelegate().bindValue(BukkitBlockShape.STONE); DelegatingBlockState state = (DelegatingBlockState) FastNMS.INSTANCE.method$Block$defaultState(block); @@ -142,14 +108,9 @@ public final class BukkitBlockManager extends AbstractBlockManager { HandlerList.unregisterAll(this.blockEventListener); } - @Override - public Map soundMapper() { - return this.soundMapper; - } - @Override public void delayedLoad() { - this.resetPacketListeners(); + this.plugin.networkManager().registerBlockStatePacketListeners(this.blockStateMappings); // 重置方块映射表 super.delayedLoad(); } @@ -180,47 +141,39 @@ public final class BukkitBlockManager extends AbstractBlockManager { if (state != null) { return state.customBlockState(); } + return createVanillaBlockState(blockState); + } + + @Override + public BlockStateWrapper createVanillaBlockState(String blockState) { + Object state = parseBlockState(blockState); + if (state == null) return null; + return BlockStateUtils.toBlockStateWrapper(state); + } + + @Nullable + private Object parseBlockState(String state) { + if (this.blockStateCache.containsKey(state)) { + return this.blockStateCache.get(state); + } try { - BlockData blockData = Bukkit.createBlockData(blockState); - return BlockStateUtils.toBlockStateWrapper(blockData); - } catch (IllegalArgumentException e) { + Object registryOrLookUp = MBuiltInRegistries.BLOCK; + if (CoreReflections.method$Registry$asLookup != null) { + registryOrLookUp = CoreReflections.method$Registry$asLookup.invoke(registryOrLookUp); + } + Object result = CoreReflections.method$BlockStateParser$parseForBlock.invoke(null, registryOrLookUp, state, false); + Object resultState = CoreReflections.method$BlockStateParser$BlockResult$blockState.invoke(result); + this.blockStateCache.put(state, resultState); + return resultState; + } catch (Exception e) { + Debugger.BLOCK.warn(() -> "Failed to create block state: " + state, e); return null; } } @Nullable public Object getMinecraftBlockHolder(int stateId) { - return this.stateId2BlockHolder.get(stateId); - } - - @NotNull - @Override - public ImmutableBlockState getImmutableBlockStateUnsafe(int stateId) { - return this.stateId2ImmutableBlockStates[stateId - BlockStateUtils.vanillaStateSize()]; - } - - @Nullable - @Override - public ImmutableBlockState getImmutableBlockState(int stateId) { - if (!BlockStateUtils.isVanillaBlock(stateId)) { - return this.stateId2ImmutableBlockStates[stateId - BlockStateUtils.vanillaStateSize()]; - } - return null; - } - - @Override - public void addBlockInternal(Key id, CustomBlock customBlock) { - // bind appearance and real state - for (ImmutableBlockState state : customBlock.variantProvider().states()) { - ImmutableBlockState previous = this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()]; - if (previous != null && !previous.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.block.state.bind_failed", state.toString(), previous.toString(), BlockStateUtils.getBlockOwnerIdFromState(previous.customBlockState().literalObject()).toString()); - } - this.stateId2ImmutableBlockStates[state.customBlockState().registryId() - BlockStateUtils.vanillaStateSize()] = state; - this.tempBlockAppearanceConvertor.put(state.customBlockState().registryId(), state.vanillaBlockState().registryId()); - this.appearanceToRealState.computeIfAbsent(state.vanillaBlockState().registryId(), k -> new IntArrayList()).add(state.customBlockState().registryId()); - } - super.addBlockInternal(id, customBlock); + return this.customBlockHolders[stateId - BlockStateUtils.vanillaBlockStateCount()]; } @Override @@ -233,19 +186,67 @@ public final class BukkitBlockManager extends AbstractBlockManager { return BlockStateUtils.getBlockOwnerIdFromState(BlockStateUtils.idToBlockState(id)); } - @Override - public int availableAppearances(Key blockType) { - return Optional.ofNullable(this.registeredRealBlockSlots.get(blockType)).orElse(0); + @SuppressWarnings("unchecked") + private void initFireBlock() { + try { + this.igniteOdds = (Map) CoreReflections.field$FireBlock$igniteOdds.get(MBlocks.FIRE); + this.burnOdds = (Map) CoreReflections.field$FireBlock$burnOdds.get(MBlocks.FIRE); + } catch (IllegalAccessException e) { + this.plugin.logger().warn("Failed to get ignite odds", e); + } } - @NotNull - public Map> blockAppearanceArranger() { - return this.blockAppearanceArranger; + private void initVanillaBlockSettings() { + try { + for (int i = 0; i < this.vanillaBlockStateCount; i++) { + Object blockState = BlockStateUtils.idToBlockState(i); + // 确保缓存已被激活 + CoreReflections.method$BlockStateBase$initCache.invoke(blockState); + BlockSettings settings = BlockSettings.of() + .pushReaction(PushReaction.VALUES[((Enum) CoreReflections.field$BlockStateBase$pushReaction.get(blockState)).ordinal()]) + .mapColor(MapColor.get(CoreReflections.field$MapColor$id.getInt(CoreReflections.field$BlockStateBase$mapColor.get(blockState)))) + .canOcclude(FastNMS.INSTANCE.method$BlockStateBase$canOcclude(blockState) ? Tristate.TRUE : Tristate.FALSE) + .isRandomlyTicking(CoreReflections.field$BlockStateBase$isRandomlyTicking.getBoolean(blockState)) + .hardness(CoreReflections.field$BlockStateBase$hardness.getFloat(blockState)) + .replaceable(CoreReflections.field$BlockStateBase$replaceable.getBoolean(blockState)) + .burnable(CoreReflections.field$BlockStateBase$burnable.getBoolean(blockState)) + .luminance(CoreReflections.field$BlockStateBase$lightEmission.getInt(blockState)) + .instrument(Instrument.VALUES[((Enum) CoreReflections.field$BlockStateBase$instrument.get(blockState)).ordinal()]) + .pushReaction(PushReaction.VALUES[((Enum) CoreReflections.field$BlockStateBase$pushReaction.get(blockState)).ordinal()]); + Object block = BlockStateUtils.getBlockOwner(blockState); + settings.resistance(CoreReflections.field$BlockBehaviour$explosionResistance.getFloat(block)) + .friction(CoreReflections.field$BlockBehaviour$friction.getFloat(block)) + .speedFactor(CoreReflections.field$BlockBehaviour$speedFactor.getFloat(block)) + .jumpFactor(CoreReflections.field$BlockBehaviour$jumpFactor.getFloat(block)) + .sounds(toBlockSounds(CoreReflections.field$BlockBehaviour$soundType.get(block))); + if (VersionHelper.isOrAbove1_21_2()) { + settings.blockLight(CoreReflections.field$BlockStateBase$lightBlock.getInt(blockState)); + settings.propagatesSkylightDown(CoreReflections.field$BlockStateBase$propagatesSkylightDown.getBoolean(blockState) ? Tristate.TRUE : Tristate.FALSE); + } else { + Object cache = CoreReflections.field$BlockStateBase$cache.get(blockState); + settings.blockLight(CoreReflections.field$BlockStateBase$Cache$lightBlock.getInt(cache)); + settings.propagatesSkylightDown(CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(cache) ? Tristate.TRUE : Tristate.FALSE); + } + this.vanillaBlockSettings[i] = settings; + } + } catch (Exception e) { + this.plugin.logger().warn("Failed to initialize vanilla block settings", e); + } } - @NotNull - public Map> realBlockArranger() { - return this.realBlockArranger; + private BlockSounds toBlockSounds(Object soundType) throws ReflectiveOperationException { + return new BlockSounds( + toSoundData(CoreReflections.field$SoundType$breakSound.get(soundType), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_0_8), + toSoundData(CoreReflections.field$SoundType$stepSound.get(soundType), SoundData.SoundValue.FIXED_0_15, SoundData.SoundValue.FIXED_1), + toSoundData(CoreReflections.field$SoundType$placeSound.get(soundType), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_0_8), + toSoundData(CoreReflections.field$SoundType$hitSound.get(soundType), SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.FIXED_0_5), + toSoundData(CoreReflections.field$SoundType$fallSound.get(soundType), SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.FIXED_0_75) + ); + } + + private SoundData toSoundData(Object soundEvent, SoundData.SoundValue volume, SoundData.SoundValue pitch) { + Key soundId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.field$SoundEvent$location(soundEvent)); + return new SoundData(soundId, volume, pitch); } private void initMirrorRegistry() { @@ -263,419 +264,126 @@ public final class BukkitBlockManager extends AbstractBlockManager { holder.bindValue(emptyBlock); } - private void resetPacketListeners() { - Map finalMapping = new HashMap<>(this.blockAppearanceMapper); - int stoneId = BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState); - for (int custom : this.internalId2StateId.values()) { - finalMapping.put(custom, stoneId); - } - finalMapping.putAll(this.tempBlockAppearanceConvertor); - BukkitNetworkManager.instance().registerBlockStatePacketListeners(finalMapping, RegistryUtils.currentBlockRegistrySize()); - } - - private void initVanillaRegistry() { - int vanillaStateCount = RegistryUtils.currentBlockRegistrySize(); - this.plugin.logger().info("Vanilla block count: " + vanillaStateCount); - BlockStateUtils.init(vanillaStateCount); - } - @Override protected CustomBlock.Builder platformBuilder(Key id) { return BukkitCustomBlock.builder(id); } - @SuppressWarnings("unchecked") - private void registerBlocks() { - this.plugin.logger().info("Registering blocks. Please wait..."); - try { - ImmutableMap.Builder builder1 = ImmutableMap.builder(); - ImmutableMap.Builder builder2 = ImmutableMap.builder(); - ImmutableMap.Builder> builder3 = ImmutableMap.builder(); - ImmutableMap.Builder builder4 = ImmutableMap.builder(); - Set affectedBlockSounds = new HashSet<>(); - Map> affectedDoors = new IdentityHashMap<>(); - Set affectedBlocks = new HashSet<>(); - List order = new ArrayList<>(); - - unfreezeRegistry(); - - int counter = 0; - for (Map.Entry baseBlockAndItsCount : this.registeredRealBlockSlots.entrySet()) { - counter = registerBlockVariants(baseBlockAndItsCount, counter, builder1, builder2, builder3, builder4, affectedBlockSounds, order); - } - - freezeRegistry(); - this.plugin.logger().info("Registered block count: " + counter); - this.customBlockCount = counter; - this.internalId2StateId = builder1.build(); - this.stateId2BlockHolder = builder2.build(); - this.realBlockArranger = builder3.build(); - this.registeredBlocks = builder4.build(); - this.blockRegisterOrder = ImmutableList.copyOf(order); - if (MCUtils.ceilLog2(BlockStateUtils.vanillaStateSize() + counter) == MCUtils.ceilLog2(BlockStateUtils.vanillaStateSize())) { - PalettedContainer.NEED_DOWNGRADE = false; - } - for (Object block : (Iterable) MBuiltInRegistries.BLOCK) { - Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(block); - if (affectedBlockSounds.contains(soundType)) { - Object state = FastNMS.INSTANCE.method$Block$defaultState(block); - if (BlockStateUtils.isVanillaBlock(state)) { - affectedBlocks.add(block); - } - } - } - - affectedBlocks.remove(MBlocks.FIRE); - affectedBlocks.remove(MBlocks.SOUL_FIRE); - - this.affectedSoundBlocks = ImmutableSet.copyOf(affectedBlocks); - - ImmutableMap.Builder soundMapperBuilder = ImmutableMap.builder(); - for (Object soundType : affectedBlockSounds) { - for (Field field : List.of(CoreReflections.field$SoundType$placeSound, CoreReflections.field$SoundType$fallSound, CoreReflections.field$SoundType$hitSound, CoreReflections.field$SoundType$stepSound, CoreReflections.field$SoundType$breakSound)) { - Object soundEvent = field.get(soundType); - Key previousId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(soundEvent).toString()); - soundMapperBuilder.put(previousId, Key.of(previousId.namespace(), "replaced." + previousId.value())); - } - } - - Predicate predicate = it -> this.realBlockArranger.containsKey(it); - Consumer soundCallback = s -> soundMapperBuilder.put(s, Key.of("replaced." + s.value())); - BiConsumer> affectedBlockCallback = affectedDoors::put; - Function soundMapper = (k) -> SoundData.of(k, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f)); - collectDoorSounds(predicate, Sounds.WOODEN_TRAPDOOR_OPEN, Sounds.WOODEN_TRAPDOOR_CLOSE, Sounds.WOODEN_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.NETHER_WOOD_TRAPDOOR_OPEN, Sounds.NETHER_WOOD_TRAPDOOR_CLOSE, Sounds.NETHER_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.BAMBOO_WOOD_TRAPDOOR_OPEN, Sounds.BAMBOO_WOOD_TRAPDOOR_CLOSE, Sounds.BAMBOO_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.CHERRY_WOOD_TRAPDOOR_OPEN, Sounds.CHERRY_WOOD_TRAPDOOR_CLOSE, Sounds.CHERRY_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.COPPER_TRAPDOOR_OPEN, Sounds.COPPER_TRAPDOOR_CLOSE, Sounds.COPPER_TRAPDOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.WOODEN_DOOR_OPEN, Sounds.WOODEN_DOOR_CLOSE, Sounds.WOODEN_DOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.NETHER_WOOD_DOOR_OPEN, Sounds.NETHER_WOOD_DOOR_CLOSE, Sounds.NETHER_DOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.BAMBOO_WOOD_DOOR_OPEN, Sounds.BAMBOO_WOOD_DOOR_CLOSE, Sounds.BAMBOO_DOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.CHERRY_WOOD_DOOR_OPEN, Sounds.CHERRY_WOOD_DOOR_CLOSE, Sounds.CHERRY_DOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.COPPER_DOOR_OPEN, Sounds.COPPER_DOOR_CLOSE, Sounds.COPPER_DOORS, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.WOODEN_FENCE_GATE_OPEN, Sounds.WOODEN_FENCE_GATE_CLOSE, Sounds.WOODEN_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.NETHER_WOOD_FENCE_GATE_OPEN, Sounds.NETHER_WOOD_FENCE_GATE_CLOSE, Sounds.NETHER_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.BAMBOO_WOOD_FENCE_GATE_OPEN, Sounds.BAMBOO_WOOD_FENCE_GATE_CLOSE, Sounds.BAMBOO_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback); - collectDoorSounds(predicate, Sounds.CHERRY_WOOD_FENCE_GATE_OPEN, Sounds.CHERRY_WOOD_FENCE_GATE_CLOSE, Sounds.CHERRY_FENCE_GATES, soundMapper, soundCallback, affectedBlockCallback); - this.affectedOpenableBlockSounds = ImmutableMap.copyOf(affectedDoors); - this.soundMapper = soundMapperBuilder.buildKeepingLast(); - } catch (Throwable e) { - plugin.logger().warn("Failed to inject blocks.", e); + // 注册服务端侧的真实方块 + private void registerServerSideCustomBlocks(int count) { + // 这个会影响全局调色盘 + if (MCUtils.ceilLog2(this.vanillaBlockStateCount + count) == MCUtils.ceilLog2(this.vanillaBlockStateCount)) { + PalettedContainer.NEED_DOWNGRADE = false; } - } - - private void collectDoorSounds(Predicate isUsedForCustomBlock, - Key openSound, - Key closeSound, - List doors, - Function soundMapper, - Consumer soundCallback, - BiConsumer> affectedBlockCallback) { - for (Key d : doors) { - if (isUsedForCustomBlock.test(d)) { - soundCallback.accept(openSound); - soundCallback.accept(closeSound); - for (Key door : doors) { - Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(door)); - if (block != null) { - affectedBlockCallback.accept(block, Pair.of(soundMapper.apply(Key.of("replaced." + openSound.value())), soundMapper.apply(Key.of("replaced." + closeSound.value())))); - } + try { + unfreezeRegistry(); + for (int i = 0; i < count; i++) { + Key customBlockId = BlockManager.createCustomBlockKey(i); + DelegatingBlock customBlock; + try { + customBlock = BlockGenerator.generateBlock(customBlockId); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to generate custom block " + customBlockId, t); + break; + } + this.customBlocks[i] = customBlock; + try { + Object resourceLocation = KeyUtils.toResourceLocation(customBlockId); + Object blockHolder = CoreReflections.method$Registry$registerForHolder.invoke(null, MBuiltInRegistries.BLOCK, resourceLocation, customBlock); + this.customBlockHolders[i] = blockHolder; + CoreReflections.method$Holder$Reference$bindValue.invoke(blockHolder, customBlock); + CoreReflections.field$Holder$Reference$tags.set(blockHolder, Set.of()); + DelegatingBlockState newBlockState = (DelegatingBlockState) FastNMS.INSTANCE.method$Block$defaultState(customBlock); + this.customBlockStates[i] = newBlockState; + CoreReflections.method$IdMapper$add.invoke(CoreReflections.instance$Block$BLOCK_STATE_REGISTRY, newBlockState); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to register custom block " + customBlockId, e); } - break; } + } finally { + freezeRegistry(); } } public Object cachedUpdateTagsPacket() { - return cachedUpdateTagsPacket; + return this.cachedUpdateTagsPacket; } - private void loadMappingsAndAdditionalBlocks() { - this.plugin.logger().info("Loading mappings.yml."); - Path mappingsFile = this.plugin.dataFolderPath().resolve("mappings.yml"); - if (!Files.exists(mappingsFile)) { - this.plugin.saveResource("mappings.yml"); - } - Path additionalFile = this.plugin.dataFolderPath().resolve("additional-real-blocks.yml"); - if (!Files.exists(additionalFile)) { - this.plugin.saveResource("additional-real-blocks.yml"); - } - Yaml yaml = new Yaml(new StringKeyConstructor(mappingsFile, new LoaderOptions())); - Map blockTypeCounter = new LinkedHashMap<>(); - try (InputStream is = Files.newInputStream(mappingsFile)) { - Map blockStateMappings = loadBlockStateMappings(yaml.load(is)); - this.validateBlockStateMappings(mappingsFile, blockStateMappings); - Map stateMap = new Int2ObjectOpenHashMap<>(); - Map appearanceMapper = new Int2IntOpenHashMap(); - Map> appearanceArranger = new HashMap<>(); - for (Map.Entry entry : blockStateMappings.entrySet()) { - this.processBlockStateMapping(mappingsFile, entry, stateMap, blockTypeCounter, appearanceMapper, appearanceArranger); - } - this.blockAppearanceMapper = ImmutableMap.copyOf(appearanceMapper); - this.blockAppearanceArranger = ImmutableMap.copyOf(appearanceArranger); - this.plugin.logger().info("Freed " + this.blockAppearanceMapper.size() + " block state appearances."); - } catch (IOException e) { - throw new RuntimeException("Failed to init mappings.yml", e); - } - try (InputStream is = Files.newInputStream(additionalFile)) { - this.registeredRealBlockSlots = this.buildRegisteredRealBlockSlots(blockTypeCounter, yaml.load(is)); - } catch (IOException e) { - throw new RuntimeException("Failed to init additional-real-blocks.yml", e); - } - } - - private void recordVanillaNoteBlocks() { + private void markVanillaNoteBlocks() { try { - Object resourceLocation = KeyUtils.toResourceLocation(BlockKeys.NOTE_BLOCK); - Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, resourceLocation); + Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(BlockKeys.NOTE_BLOCK)); Object stateDefinition = CoreReflections.field$Block$StateDefinition.get(block); @SuppressWarnings("unchecked") ImmutableList states = (ImmutableList) CoreReflections.field$StateDefinition$states.get(stateDefinition); - for (Object state : states) { - BlockStateUtils.CLIENT_SIDE_NOTE_BLOCKS.put(state, new Object()); - } + CLIENT_SIDE_NOTE_BLOCKS.addAll(states); } catch (ReflectiveOperationException e) { - plugin.logger().warn("Failed to init vanilla note block", e); - } - } - - @Nullable - public Key replaceSoundIfExist(Key id) { - return this.soundMapper.get(id); - } - - public boolean isBlockSoundRemoved(Object block) { - return this.affectedSoundBlocks.contains(block); - } - - public boolean isOpenableBlockSoundRemoved(Object block) { - return this.affectedOpenableBlockSounds.containsKey(block); - } - - public SoundData getRemovedOpenableBlockSound(Object block, boolean open) { - return open ? this.affectedOpenableBlockSounds.get(block).left() : this.affectedOpenableBlockSounds.get(block).right(); - } - - private Map loadBlockStateMappings(Map mappings) { - Map blockStateMappings = new LinkedHashMap<>(); - for (Map.Entry entry : mappings.entrySet()) { - if (entry.getValue() instanceof String afterValue) { - blockStateMappings.put(entry.getKey(), afterValue); - } - } - return blockStateMappings; - } - - private void validateBlockStateMappings(Path mappingFile, Map blockStateMappings) { - Map temp = new HashMap<>(blockStateMappings); - for (Map.Entry entry : temp.entrySet()) { - String state = entry.getValue(); - if (blockStateMappings.containsKey(state)) { - String after = blockStateMappings.remove(state); - plugin.logger().warn(mappingFile, "'" + state + ": " + after + "' is invalid because '" + state + "' has already been used as a base block."); - } - } - } - - private void processBlockStateMapping(Path mappingFile, - Map.Entry entry, - Map stateMap, - Map counter, - Map mapper, - Map> arranger) { - Object before = createBlockState(mappingFile, entry.getKey()); - Object after = createBlockState(mappingFile, entry.getValue()); - if (before == null || after == null) return; - - int beforeId = BlockStateUtils.blockStateToId(before); - int afterId = BlockStateUtils.blockStateToId(after); - - Integer previous = mapper.put(beforeId, afterId); - if (previous == null) { - Key key = blockOwnerFromString(entry.getKey()); - counter.compute(key, (k, count) -> count == null ? 1 : count + 1); - stateMap.put(beforeId, entry.getKey()); - stateMap.put(afterId, entry.getValue()); - arranger.computeIfAbsent(key, (k) -> new IntArrayList()).add(beforeId); - } else { - String previousState = stateMap.get(previous); - plugin.logger().warn(mappingFile, "Duplicate entry: '" + previousState + "' equals '" + entry.getKey() + "'"); - } - } - - private Key blockOwnerFromString(String stateString) { - int index = stateString.indexOf('['); - if (index == -1) { - return Key.of(stateString); - } else { - return Key.of(stateString.substring(0, index)); - } - } - - private Object createBlockState(Path mappingFile, String state) { - try { - Object registryOrLookUp = MBuiltInRegistries.BLOCK; - if (CoreReflections.method$Registry$asLookup != null) { - registryOrLookUp = CoreReflections.method$Registry$asLookup.invoke(registryOrLookUp); - } - Object result = CoreReflections.method$BlockStateParser$parseForBlock.invoke(null, registryOrLookUp, state, false); - return CoreReflections.method$BlockStateParser$BlockResult$blockState.invoke(result); - } catch (Exception e) { - this.plugin.logger().warn(mappingFile, "'" + state + "' is not a valid block state."); - return null; - } - } - - private LinkedHashMap buildRegisteredRealBlockSlots(Map counter, Map additionalYaml) { - LinkedHashMap map = new LinkedHashMap<>(counter); - for (Map.Entry entry : additionalYaml.entrySet()) { - Key blockType = Key.of(entry.getKey()); - if (entry.getValue() instanceof Integer i) { - int previous = map.getOrDefault(blockType, 0); - if (previous == 0) { - map.put(blockType, i); - this.plugin.logger().info("Loaded " + blockType + " with " + i + " real block states"); - } else { - map.put(blockType, i + previous); - this.plugin.logger().info("Loaded " + blockType + " with " + previous + " appearances and " + (i + previous) + " real block states"); - } - } - } - return map; - } - - private void unfreezeRegistry() throws IllegalAccessException { - CoreReflections.field$MappedRegistry$frozen.set(MBuiltInRegistries.BLOCK, false); - CoreReflections.field$MappedRegistry$unregisteredIntrusiveHolders.set(MBuiltInRegistries.BLOCK, new IdentityHashMap<>()); - } - - private void freezeRegistry() throws IllegalAccessException { - CoreReflections.field$MappedRegistry$frozen.set(MBuiltInRegistries.BLOCK, true); - } - - private int registerBlockVariants(Map.Entry blockWithCount, - int counter, - ImmutableMap.Builder builder1, - ImmutableMap.Builder builder2, - ImmutableMap.Builder> builder3, - ImmutableMap.Builder builder4, - Set affectSoundTypes, - List order) throws Exception { - Key clientSideBlockType = blockWithCount.getKey(); - boolean isNoteBlock = clientSideBlockType.equals(BlockKeys.NOTE_BLOCK); - Object clientSideBlock = getBlockFromRegistry(createResourceLocation(clientSideBlockType)); - int amount = blockWithCount.getValue(); - - List stateIds = new IntArrayList(); - - for (int i = 0; i < amount; i++) { - Key realBlockKey = createRealBlockKey(clientSideBlockType, i); - Object blockProperties = createBlockProperties(realBlockKey); - - Object newRealBlock; - Object newBlockState; - Object blockHolder; - Object resourceLocation = createResourceLocation(realBlockKey); - - try { - newRealBlock = BlockGenerator.generateBlock(clientSideBlockType, clientSideBlock, blockProperties); - } catch (Throwable throwable) { - this.plugin.logger().warn("Failed to generate dynamic block class", throwable); - continue; - } - - blockHolder = CoreReflections.method$Registry$registerForHolder.invoke(null, MBuiltInRegistries.BLOCK, resourceLocation, newRealBlock); - CoreReflections.method$Holder$Reference$bindValue.invoke(blockHolder, newRealBlock); - CoreReflections.field$Holder$Reference$tags.set(blockHolder, Set.of()); - - newBlockState = FastNMS.INSTANCE.method$Block$defaultState(newRealBlock); - CoreReflections.method$IdMapper$add.invoke(CoreReflections.instance$Block$BLOCK_STATE_REGISTRY, newBlockState); - - if (isNoteBlock) { - BlockStateUtils.CLIENT_SIDE_NOTE_BLOCKS.put(newBlockState, new Object()); - } - - int stateId = BlockStateUtils.vanillaStateSize() + counter; - - builder1.put(realBlockKey, stateId); - builder2.put(stateId, blockHolder); - builder4.put(realBlockKey, (DelegatingBlock) newRealBlock); - stateIds.add(stateId); - - this.blocksToDeceive.add(Tuple.of(newRealBlock, clientSideBlockType, isNoteBlock)); - order.add(realBlockKey); - counter++; - } - - builder3.put(clientSideBlockType, stateIds); - Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(clientSideBlock); - affectSoundTypes.add(soundType); - return counter; - } - - private Object createResourceLocation(Key key) { - return FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath(key.namespace(), key.value()); - } - - private Object getBlockFromRegistry(Object resourceLocation) { - return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, resourceLocation); - } - - private Key createRealBlockKey(Key replacedBlock, int index) { - return Key.of(Key.DEFAULT_NAMESPACE, replacedBlock.value() + "_" + index); - } - - private Object createBlockProperties(Key realBlockKey) throws Exception { - Object blockProperties = CoreReflections.method$BlockBehaviour$Properties$of.invoke(null); - Object realBlockResourceLocation = createResourceLocation(realBlockKey); - Object realBlockResourceKey = CoreReflections.method$ResourceKey$create.invoke(null, MRegistries.BLOCK, realBlockResourceLocation); - if (CoreReflections.field$BlockBehaviour$Properties$id != null) { - CoreReflections.field$BlockBehaviour$Properties$id.set(blockProperties, realBlockResourceKey); - } - return blockProperties; - } - - @SuppressWarnings("unchecked") - private void deceiveBukkit() { - try { - Map magicMap = (Map) CraftBukkitReflections.field$CraftMagicNumbers$BLOCK_MATERIAL.get(null); - Map factories = (Map) CraftBukkitReflections.field$CraftBlockStates$FACTORIES.get(null); - for (Tuple tuple : this.blocksToDeceive) { - deceiveBukkit(tuple.left(), tuple.mid(), tuple.right(), magicMap, factories); - } - this.blocksToDeceive.clear(); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to deceive bukkit", e); - } - } - - private void deceiveBukkit(Object newBlock, Key replacedBlock, boolean isNoteBlock, Map magicMap, Map factories) { - if (isNoteBlock) { - magicMap.put(newBlock, Material.STONE); - } else { - Material material = org.bukkit.Registry.MATERIAL.get(new NamespacedKey(replacedBlock.namespace(), replacedBlock.value())); - if (CraftBukkitReflections.clazz$CraftBlockStates$BlockEntityStateFactory.isInstance(factories.get(material))) { - magicMap.put(newBlock, Material.STONE); - } else { - magicMap.put(newBlock, material); - } + this.plugin.logger().warn("Failed to init vanilla note block", e); } } @Override - protected int getBlockRegistryId(Key id) { + protected void setVanillaBlockTags(Key id, List tags) { Object block = FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id)); - return FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, block).orElseThrow(() -> new IllegalStateException("Block " + id + " not found")); + this.clientBoundTags.put(FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, block).orElseThrow(() -> new IllegalStateException("Block " + id + " not found")), tags); + } + + public boolean isBlockSoundRemoved(Object block) { + return this.replacedBlockSounds.contains(block); + } + + private void unfreezeRegistry() { + try { + CoreReflections.field$MappedRegistry$frozen.set(MBuiltInRegistries.BLOCK, false); + CoreReflections.field$MappedRegistry$unregisteredIntrusiveHolders.set(MBuiltInRegistries.BLOCK, new IdentityHashMap<>()); + } catch (IllegalAccessException e) { + this.plugin.logger().warn("Failed to unfreeze block registry", e); + } + } + + private void freezeRegistry() { + try { + CoreReflections.field$MappedRegistry$frozen.set(MBuiltInRegistries.BLOCK, true); + } catch (IllegalAccessException e) { + this.plugin.logger().warn("Failed to freeze block registry", e); + } + } + + @SuppressWarnings("unchecked") + private void deceiveBukkitRegistry() { + try { + Map magicMap = (Map) CraftBukkitReflections.field$CraftMagicNumbers$BLOCK_MATERIAL.get(null); + for (DelegatingBlock customBlock : this.customBlocks) { + magicMap.put(customBlock, Material.STONE); + } + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to deceive bukkit magic blocks", e); + } } @Override protected boolean isVanillaBlock(Key id) { - if (!id.namespace().equals("minecraft")) { + if (!id.namespace().equals("minecraft")) return false; - } - if (id.value().equals("air")) { + if (id.value().equals("air")) return true; - } return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.BLOCK, KeyUtils.toResourceLocation(id)) != MBlocks.AIR; } + + public boolean isBurnable(Object blockState) { + Object blockOwner = BlockStateUtils.getBlockOwner(blockState); + return this.igniteOdds.getOrDefault(blockOwner, 0) > 0; + } + + @Override + public int vanillaBlockStateCount() { + return this.vanillaBlockStateCount; + } + + public boolean isOpenableBlockSoundRemoved(Object blockOwner) { + return false; + } + + public SoundData getRemovedOpenableBlockSound(Object blockOwner, boolean b) { + return null; + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockStateWrapper.java index cafb79317..8d0190d76 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockStateWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockStateWrapper.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.bukkit.block; import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.util.Key; public class BukkitBlockStateWrapper implements BlockStateWrapper { private final Object blockState; @@ -20,4 +21,14 @@ public class BukkitBlockStateWrapper implements BlockStateWrapper { public int registryId() { return this.registryId; } + + @Override + public String toString() { + return this.blockState.toString(); + } + + @Override + public Key ownerId() { + return null; + } } 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 ae91184a2..b831a0cde 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 @@ -32,8 +32,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; public final class BukkitCustomBlock extends AbstractCustomBlock { - private static final Object ALWAYS_FALSE = FastNMS.INSTANCE.method$StatePredicate$always(false); - private static final Object ALWAYS_TRUE = FastNMS.INSTANCE.method$StatePredicate$always(true); private BukkitCustomBlock( @NotNull Key id, @@ -71,128 +69,6 @@ public final class BukkitCustomBlock extends AbstractCustomBlock { return (LootTable) super.lootTable(); } - @Override - protected void applyPlatformSettings() { - try { - for (ImmutableBlockState immutableBlockState : variantProvider().states()) { - if (immutableBlockState.vanillaBlockState() == null) { - CraftEngine.instance().logger().warn("Could not find vanilla visual block state for " + immutableBlockState + ". This might cause errors!"); - continue; - } else if (immutableBlockState.customBlockState() == null) { - CraftEngine.instance().logger().warn("Could not find real block state for " + immutableBlockState + ". This might cause errors!"); - continue; - } - DelegatingBlockState nmsState = (DelegatingBlockState) immutableBlockState.customBlockState().literalObject(); - nmsState.setBlockState(immutableBlockState); - BlockSettings settings = immutableBlockState.settings(); - - // set block properties - CoreReflections.field$BlockStateBase$lightEmission.set(nmsState, settings.luminance()); - CoreReflections.field$BlockStateBase$burnable.set(nmsState, settings.burnable()); - CoreReflections.field$BlockStateBase$hardness.set(nmsState, settings.hardness()); - CoreReflections.field$BlockStateBase$replaceable.set(nmsState, settings.replaceable()); - Object mcMapColor = CoreReflections.method$MapColor$byId.invoke(null, settings.mapColor().id); - CoreReflections.field$BlockStateBase$mapColor.set(nmsState, mcMapColor); - Object mcInstrument = ((Object[]) CoreReflections.method$NoteBlockInstrument$values.invoke(null))[settings.instrument().ordinal()]; - CoreReflections.field$BlockStateBase$instrument.set(nmsState, mcInstrument); - Object pushReaction = ((Object[]) CoreReflections.method$PushReaction$values.invoke(null))[settings.pushReaction().ordinal()]; - CoreReflections.field$BlockStateBase$pushReaction.set(nmsState, pushReaction); - - boolean canOcclude = settings.canOcclude() == Tristate.UNDEFINED ? BlockStateUtils.isOcclude(immutableBlockState.vanillaBlockState().literalObject()) : settings.canOcclude().asBoolean(); - CoreReflections.field$BlockStateBase$canOcclude.set(nmsState, canOcclude); - - boolean useShapeForLightOcclusion = settings.useShapeForLightOcclusion() == Tristate.UNDEFINED ? CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.getBoolean(immutableBlockState.vanillaBlockState().literalObject()) : settings.useShapeForLightOcclusion().asBoolean(); - CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.set(nmsState, useShapeForLightOcclusion); - - CoreReflections.field$BlockStateBase$isRedstoneConductor.set(nmsState, settings.isRedstoneConductor().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE); - CoreReflections.field$BlockStateBase$isSuffocating.set(nmsState, settings.isSuffocating().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE); - CoreReflections.field$BlockStateBase$isViewBlocking.set(nmsState, settings.isViewBlocking() == Tristate.UNDEFINED ? settings.isSuffocating().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE : (settings.isViewBlocking().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE)); - - // set parent block properties - DelegatingBlock nmsBlock = (DelegatingBlock) BlockStateUtils.getBlockOwner(nmsState); - ObjectHolder shapeHolder = nmsBlock.shapeDelegate(); - shapeHolder.bindValue(new BukkitBlockShape(immutableBlockState.vanillaBlockState().literalObject(), Optional.ofNullable(immutableBlockState.settings().supportShapeBlockState()).map(it -> { - try { - Object blockState = BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(it)); - if (!BlockStateUtils.isVanillaBlock(blockState)) { - throw new IllegalArgumentException("BlockState is not a Vanilla block"); - } - return blockState; - } catch (IllegalArgumentException e) { - CraftEngine.instance().logger().warn("Illegal shape block state: " + it, e); - return null; - } - }).orElse(null))); - // bind behavior - ObjectHolder behaviorHolder = nmsBlock.behaviorDelegate(); - behaviorHolder.bindValue(super.behavior); - // set block side properties - CoreReflections.field$BlockBehaviour$explosionResistance.set(nmsBlock, settings.resistance()); - CoreReflections.field$BlockBehaviour$friction.set(nmsBlock, settings.friction()); - CoreReflections.field$BlockBehaviour$speedFactor.set(nmsBlock, settings.speedFactor()); - CoreReflections.field$BlockBehaviour$jumpFactor.set(nmsBlock, settings.jumpFactor()); - CoreReflections.field$BlockBehaviour$soundType.set(nmsBlock, SoundUtils.toSoundType(settings.sounds())); - // init cache - CoreReflections.method$BlockStateBase$initCache.invoke(nmsState); - boolean isConditionallyFullOpaque = canOcclude & useShapeForLightOcclusion; - if (!VersionHelper.isOrAbove1_21_2()) { - CoreReflections.field$BlockStateBase$isConditionallyFullOpaque.set(nmsState, isConditionallyFullOpaque); - } - // modify cache - if (VersionHelper.isOrAbove1_21_2()) { - int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(immutableBlockState.vanillaBlockState().literalObject()); - // set block light - CoreReflections.field$BlockStateBase$lightBlock.set(nmsState, blockLight); - // set propagates skylight - if (settings.propagatesSkylightDown() == Tristate.TRUE) { - CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, true); - } else if (settings.propagatesSkylightDown() == Tristate.FALSE) { - CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, false); - } else { - CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, CoreReflections.field$BlockStateBase$propagatesSkylightDown.getBoolean(immutableBlockState.vanillaBlockState().literalObject())); - } - } else { - Object cache = CoreReflections.field$BlockStateBase$cache.get(nmsState); - int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$Cache$lightBlock.getInt(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().literalObject())); - // set block light - CoreReflections.field$BlockStateBase$Cache$lightBlock.set(cache, blockLight); - // set propagates skylight - if (settings.propagatesSkylightDown() == Tristate.TRUE) { - CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, true); - } else if (settings.propagatesSkylightDown() == Tristate.FALSE) { - CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, false); - } else { - CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(CoreReflections.field$BlockStateBase$cache.get(immutableBlockState.vanillaBlockState().literalObject()))); - } - if (!isConditionallyFullOpaque) { - CoreReflections.field$BlockStateBase$opacityIfCached.set(nmsState, blockLight); - } - } - // set fluid later - if (settings.fluidState()) { - CoreReflections.field$BlockStateBase$fluidState.set(nmsState, CoreReflections.method$FlowingFluid$getSource.invoke(MFluids.WATER, false)); - } else { - CoreReflections.field$BlockStateBase$fluidState.set(nmsState, MFluids.EMPTY$defaultState); - } - // set random tick later - CoreReflections.field$BlockStateBase$isRandomlyTicking.set(nmsState, settings.isRandomlyTicking()); - // bind tags - Object holder = BukkitCraftEngine.instance().blockManager().getMinecraftBlockHolder(immutableBlockState.customBlockState().registryId()); - Set tags = new HashSet<>(); - for (Key tag : settings.tags()) { - tags.add(CoreReflections.method$TagKey$create.invoke(null, MRegistries.BLOCK, KeyUtils.toResourceLocation(tag))); - } - CoreReflections.field$Holder$Reference$tags.set(holder, tags); - // set burning properties - if (settings.burnable()) { - CoreReflections.method$FireBlock$setFlammable.invoke(MBlocks.FIRE, nmsBlock, settings.burnChance(), settings.fireSpreadChance()); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to init block settings", e); - } - } - public static Builder builder(Key id) { return new BuilderImpl(id); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java index bace95fe2..8a807c7e0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/BushBlockBehavior.java @@ -65,7 +65,7 @@ public class BushBlockBehavior extends AbstractCanSurviveBlockBehavior { if (material != null) { if (index == -1) { // vanilla - mcBlocks.addAll(BlockStateUtils.getAllVanillaBlockStates(blockType)); + mcBlocks.addAll(BlockStateUtils.getPossibleBlockStates(blockType)); } else { mcBlocks.add(BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(blockStateStr))); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java index 56e68b810..4b286d52e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -10,10 +10,8 @@ import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.Callable; -import java.util.stream.Stream; public class ChimeBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java index f2e4d9987..958a1e37a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DirectionalAttachedBlockBehavior.java @@ -163,7 +163,7 @@ public class DirectionalAttachedBlockBehavior extends BukkitBlockBehavior { if (material != null) { if (index == -1) { // vanilla - mcBlocks.addAll(BlockStateUtils.getAllVanillaBlockStates(blockType)); + mcBlocks.addAll(BlockStateUtils.getPossibleBlockStates(blockType)); } else { mcBlocks.add(BlockStateUtils.blockDataToBlockState(Bukkit.createBlockData(blockStateStr))); } 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 48a99aa1f..f71bbf15b 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 @@ -11,6 +11,7 @@ import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; +import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldPosition; @@ -23,11 +24,15 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final float hurtAmount; private final int maxHurt; + private final SoundData landSound; + private final SoundData destroySound; - public FallingBlockBehavior(CustomBlock block, float hurtAmount, int maxHurt) { + public FallingBlockBehavior(CustomBlock block, float hurtAmount, int maxHurt, SoundData landSound, SoundData destroySound) { super(block); this.hurtAmount = hurtAmount; this.maxHurt = maxHurt; + this.landSound = landSound; + this.destroySound = destroySound; } @Override @@ -80,10 +85,11 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { Object blockState = CoreReflections.field$FallingBlockEntity$blockState.get(fallingBlockEntity); Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState); if (optionalCustomState.isEmpty()) return; - ImmutableBlockState customState = optionalCustomState.get(); net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); WorldPosition position = new WorldPosition(world, CoreReflections.field$Entity$xo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$yo.getDouble(fallingBlockEntity), CoreReflections.field$Entity$zo.getDouble(fallingBlockEntity)); - world.playBlockSound(position, customState.settings().sounds().destroySound()); + if (this.destroySound != null) { + world.playBlockSound(position, this.destroySound); + } } } @@ -99,16 +105,27 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { if (immutableBlockState == null || immutableBlockState.isEmpty()) return; if (!BaseEntityData.Silent.get(entityData)) { net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); - world.playBlockSound(Vec3d.atCenterOf(LocationUtils.fromBlockPos(pos)), immutableBlockState.settings().sounds().landSound()); + if (this.landSound != null) { + world.playBlockSound(Vec3d.atCenterOf(LocationUtils.fromBlockPos(pos)), this.landSound); + } } } public static class Factory implements BlockBehaviorFactory { + + @SuppressWarnings("unchecked") @Override public BlockBehavior create(CustomBlock block, Map arguments) { float hurtAmount = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("hurt-amount", -1f), "hurt-amount"); int hurtMax = ResourceConfigUtils.getAsInt(arguments.getOrDefault("max-hurt", -1), "max-hurt"); - return new FallingBlockBehavior(block, hurtAmount, hurtMax); + Map sounds = (Map) arguments.get("sounds"); + SoundData fallSound = null; + SoundData destroySound = null; + if (sounds != null) { + fallSound = Optional.ofNullable(sounds.get("fall")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null); + destroySound = Optional.ofNullable(sounds.get("destroy")).map(obj -> SoundData.create(obj, SoundData.SoundValue.FIXED_1, SoundData.SoundValue.ranged(0.9f, 1f))).orElse(null); + } + return new FallingBlockBehavior(block, hurtAmount, hurtMax, fallSound, destroySound); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index faf8bbc09..45d9c1ef7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -242,9 +242,9 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); } else { - BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); } return new BlockItemBehavior(key); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java index 0acf2bfb3..122bb18b4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java @@ -48,9 +48,9 @@ public class DoubleHighBlockItemBehavior extends BlockItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); } else { - BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); } return new DoubleHighBlockItemBehavior(key); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java index 36a62b18d..9e058c549 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java @@ -79,9 +79,9 @@ public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); } else { - BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); } return new LiquidCollisionBlockItemBehavior(key, offset); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java index 53767eeaf..bbc48120b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java @@ -43,9 +43,9 @@ public class WallBlockItemBehavior extends BlockItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); } else { - BukkitBlockManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); } return new WallBlockItemBehavior(key); } else { 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 68205240c..31ae7e70d 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 @@ -14,6 +14,7 @@ import net.momirealms.craftengine.core.loot.VanillaLoot; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -90,8 +91,8 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme return this.vanillaLootParser; } - public class VanillaLootParser implements ConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot", "vanilla_loots", "vanilla_loot"}; + public class VanillaLootParser implements IdSectionConfigParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot"}; @Override public int loadingSequence() { @@ -126,7 +127,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme VanillaLoot vanillaLoot = blockLoots.computeIfAbsent(BlockStateUtils.blockStateToId(blockState), k -> new VanillaLoot(VanillaLoot.Type.BLOCK)); vanillaLoot.addLootTable(lootTable); } else { - for (Object blockState : BlockStateUtils.getAllVanillaBlockStates(Key.of(target))) { + for (Object blockState : BlockStateUtils.getPossibleBlockStates(Key.of(target))) { if (blockState == MBlocks.AIR$defaultState) { throw new LocalizedResourceConfigException("warning.config.vanilla_loot.block.invalid_target", target); } 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 e00b9b64b..9acb350a2 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 @@ -102,9 +102,15 @@ public class BukkitCraftEngine extends CraftEngine { this.javaPlugin = javaPlugin; } - protected void setUpConfig() { - this.translationManager = new TranslationManagerImpl(this); + protected void setUpConfigAndLocale() { this.config = new Config(this); + this.config.updateConfigCache(); + // 先读取语言后,再重载语言文件系统 + this.config.loadForcedLocale(); + this.translationManager = new TranslationManagerImpl(this); + this.translationManager.reload(); + // 最后才加载完整的config配置 + this.config.loadFullSettings(); } public void injectRegistries() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java index f47eb842e..ce6029653 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java @@ -31,54 +31,54 @@ public class DebugAppearanceStateUsageCommand extends BukkitCommandFeature assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder - .required("id", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { - @Override - public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(plugin().blockManager().blockAppearanceArranger().keySet().stream().map(it -> Suggestion.suggestion(it.toString())).toList()); - } - })) +// .required("id", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { +// @Override +// public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { +// return CompletableFuture.completedFuture(plugin().blockManager().blockAppearanceArranger().keySet().stream().map(it -> Suggestion.suggestion(it.toString())).toList()); +// } +// })) .handler(context -> { - String data = context.get("id"); - BukkitBlockManager blockManager = plugin().blockManager(); - Key baseBlockId = Key.of(data); - List appearances = blockManager.blockAppearanceArranger().get(baseBlockId); - if (appearances == null) return; - int i = 0; - Component block = Component.text(baseBlockId + ": "); - plugin().senderFactory().wrap(context.sender()).sendMessage(block); - - List batch = new ArrayList<>(); - for (int appearance : appearances) { - Component text = Component.text("|"); - List reals = blockManager.appearanceToRealStates(appearance); - if (reals == null || reals.isEmpty()) { - Component hover = Component.text(baseBlockId.value() + ":" + i).color(NamedTextColor.GREEN); - hover = hover.append(Component.newline()).append(Component.text(BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(appearance)).getAsString()).color(NamedTextColor.GREEN)); - text = text.color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover)); - } else { - Component hover = Component.text(baseBlockId.value() + ":" + i).color(NamedTextColor.RED); - List hoverChildren = new ArrayList<>(); - hoverChildren.add(Component.newline()); - hoverChildren.add(Component.text(BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(appearance)).getAsString()).color(NamedTextColor.RED)); - for (int real : reals) { - hoverChildren.add(Component.newline()); - hoverChildren.add(Component.text(blockManager.getImmutableBlockStateUnsafe(real).toString()).color(NamedTextColor.GRAY)); - } - text = text.color(NamedTextColor.RED).hoverEvent(HoverEvent.showText(hover.children(hoverChildren))); - } - batch.add(text); - i++; - if (batch.size() == 100) { - plugin().senderFactory().wrap(context.sender()) - .sendMessage(Component.text("").children(batch)); - batch.clear(); - } - } - if (!batch.isEmpty()) { - plugin().senderFactory().wrap(context.sender()) - .sendMessage(Component.text("").children(batch)); - batch.clear(); - } +// String data = context.get("id"); +// BukkitBlockManager blockManager = plugin().blockManager(); +// Key baseBlockId = Key.of(data); +// List appearances = blockManager.blockAppearanceArranger().get(baseBlockId); +// if (appearances == null) return; +// int i = 0; +// Component block = Component.text(baseBlockId + ": "); +// plugin().senderFactory().wrap(context.sender()).sendMessage(block); +// +// List batch = new ArrayList<>(); +// for (int appearance : appearances) { +// Component text = Component.text("|"); +// List reals = blockManager.appearanceToRealStates(appearance); +// if (reals == null || reals.isEmpty()) { +// Component hover = Component.text(baseBlockId.value() + ":" + i).color(NamedTextColor.GREEN); +// hover = hover.append(Component.newline()).append(Component.text(BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(appearance)).getAsString()).color(NamedTextColor.GREEN)); +// text = text.color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover)); +// } else { +// Component hover = Component.text(baseBlockId.value() + ":" + i).color(NamedTextColor.RED); +// List hoverChildren = new ArrayList<>(); +// hoverChildren.add(Component.newline()); +// hoverChildren.add(Component.text(BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(appearance)).getAsString()).color(NamedTextColor.RED)); +// for (int real : reals) { +// hoverChildren.add(Component.newline()); +// hoverChildren.add(Component.text(blockManager.getImmutableBlockStateUnsafe(real).toString()).color(NamedTextColor.GRAY)); +// } +// text = text.color(NamedTextColor.RED).hoverEvent(HoverEvent.showText(hover.children(hoverChildren))); +// } +// batch.add(text); +// i++; +// if (batch.size() == 100) { +// plugin().senderFactory().wrap(context.sender()) +// .sendMessage(Component.text("").children(batch)); +// batch.clear(); +// } +// } +// if (!batch.isEmpty()) { +// plugin().senderFactory().wrap(context.sender()) +// .sendMessage(Component.text("").children(batch)); +// batch.clear(); +// } }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java index 01531251d..04b7d0ce2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java @@ -31,45 +31,45 @@ public class DebugRealStateUsageCommand extends BukkitCommandFeature assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder - .required("id", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { - @Override - public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(plugin().blockManager().blockAppearanceArranger().keySet().stream().map(it -> Suggestion.suggestion(it.toString())).toList()); - } - })) +// .required("id", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { +// @Override +// public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { +// return CompletableFuture.completedFuture(plugin().blockManager().blockAppearanceArranger().keySet().stream().map(it -> Suggestion.suggestion(it.toString())).toList()); +// } +// })) .handler(context -> { - String data = context.get("id"); - BukkitBlockManager blockManager = plugin().blockManager(); - Key baseBlockId = Key.of(data); - List reals = blockManager.realBlockArranger().get(baseBlockId); - if (reals == null) return; - int i = 0; - Component block = Component.text(baseBlockId + ": "); - plugin().senderFactory().wrap(context.sender()).sendMessage(block); - - List batch = new ArrayList<>(100); - for (int real : reals) { - ImmutableBlockState state = blockManager.getImmutableBlockStateUnsafe(real); - if (state.isEmpty()) { - Component hover = Component.text("craftengine:" + baseBlockId.value() + "_" + i).color(NamedTextColor.GREEN); - batch.add(Component.text("|").color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover))); - } else { - Component hover = Component.text("craftengine:" + baseBlockId.value() + "_" + i).color(NamedTextColor.RED); - hover = hover.append(Component.newline()).append(Component.text(state.toString()).color(NamedTextColor.GRAY)); - batch.add(Component.text("|").color(NamedTextColor.RED).hoverEvent(HoverEvent.showText(hover))); - } - i++; - if (batch.size() == 100) { - plugin().senderFactory().wrap(context.sender()) - .sendMessage(Component.text("").children(batch)); - batch.clear(); - } - } - if (!batch.isEmpty()) { - plugin().senderFactory().wrap(context.sender()) - .sendMessage(Component.text("").children(batch)); - batch.clear(); - } +// String data = context.get("id"); +// BukkitBlockManager blockManager = plugin().blockManager(); +// Key baseBlockId = Key.of(data); +// List reals = blockManager.realBlockArranger().get(baseBlockId); +// if (reals == null) return; +// int i = 0; +// Component block = Component.text(baseBlockId + ": "); +// plugin().senderFactory().wrap(context.sender()).sendMessage(block); +// +// List batch = new ArrayList<>(100); +// for (int real : reals) { +// ImmutableBlockState state = blockManager.getImmutableBlockStateUnsafe(real); +// if (state.isEmpty()) { +// Component hover = Component.text("craftengine:" + baseBlockId.value() + "_" + i).color(NamedTextColor.GREEN); +// batch.add(Component.text("|").color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover))); +// } else { +// Component hover = Component.text("craftengine:" + baseBlockId.value() + "_" + i).color(NamedTextColor.RED); +// hover = hover.append(Component.newline()).append(Component.text(state.toString()).color(NamedTextColor.GRAY)); +// batch.add(Component.text("|").color(NamedTextColor.RED).hoverEvent(HoverEvent.showText(hover))); +// } +// i++; +// if (batch.size() == 100) { +// plugin().senderFactory().wrap(context.sender()) +// .sendMessage(Component.text("").children(batch)); +// batch.clear(); +// } +// } +// if (!batch.isEmpty()) { +// plugin().senderFactory().wrap(context.sender()) +// .sendMessage(Component.text("").children(batch)); +// batch.clear(); +// } }); } 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 2b3792085..70f1823bb 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 @@ -17,6 +17,8 @@ import net.momirealms.craftengine.bukkit.block.BukkitBlockShape; 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.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.NoteBlockChainUpdateUtils; import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.BlockKeys; @@ -199,6 +201,30 @@ public final class BlockGenerator { field$CraftEngineBlock$isTripwire = clazz$CraftEngineBlock.getField("isClientSideTripwire"); } + public static DelegatingBlock generateBlock(Key blockId) throws Throwable { + ObjectHolder behaviorHolder = new ObjectHolder<>(EmptyBlockBehavior.INSTANCE); + ObjectHolder shapeHolder = new ObjectHolder<>(STONE_SHAPE); + Object newBlockInstance = constructor$CraftEngineBlock.invoke(createEmptyBlockProperties(blockId)); + field$CraftEngineBlock$behavior.set(newBlockInstance, behaviorHolder); + field$CraftEngineBlock$shape.set(newBlockInstance, shapeHolder); + Object stateDefinitionBuilder = CoreReflections.constructor$StateDefinition$Builder.newInstance(newBlockInstance); + Object stateDefinition = CoreReflections.method$StateDefinition$Builder$create.invoke(stateDefinitionBuilder, + (Function) FastNMS.INSTANCE::method$Block$defaultState, BlockStateGenerator.instance$StateDefinition$Factory); + CoreReflections.field$Block$StateDefinition.set(newBlockInstance, stateDefinition); + CoreReflections.field$Block$defaultBlockState.set(newBlockInstance, ((ImmutableList) CoreReflections.field$StateDefinition$states.get(stateDefinition)).getFirst()); + return (DelegatingBlock) newBlockInstance; + } + + private static Object createEmptyBlockProperties(Key id) throws ReflectiveOperationException { + Object blockProperties = CoreReflections.method$BlockBehaviour$Properties$of.invoke(null); + Object resourceLocation = KeyUtils.toResourceLocation(id); + Object resourceKey = FastNMS.INSTANCE.method$ResourceKey$create(MRegistries.BLOCK, resourceLocation); + if (CoreReflections.field$BlockBehaviour$Properties$id != null) { + CoreReflections.field$BlockBehaviour$Properties$id.set(blockProperties, resourceKey); + } + return blockProperties; + } + public static Object generateBlock(Key replacedBlock, Object ownerBlock, Object properties) throws Throwable { Object ownerProperties = CoreReflections.field$BlockBehaviour$properties.get(ownerBlock); CoreReflections.field$BlockBehaviour$Properties$hasCollision.set(properties, CoreReflections.field$BlockBehaviour$Properties$hasCollision.get(ownerProperties)); 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 7ced7ec1b..48c15f39c 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 @@ -261,26 +261,33 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - public void registerBlockStatePacketListeners(Map map, int registrySize) { - int[] newMappings = new int[registrySize]; - for (int i = 0; i < registrySize; i++) { - newMappings[i] = i; - } - int[] newMappingsMOD = Arrays.copyOf(newMappings, registrySize); - for (Map.Entry entry : map.entrySet()) { - newMappings[entry.getKey()] = entry.getValue(); - if (BlockStateUtils.isVanillaBlock((int) entry.getKey())) { - newMappingsMOD[entry.getKey()] = entry.getValue(); + public void registerBlockStatePacketListeners(int[] blockStateMappings) { + int stoneId = BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState); + int vanillaBlocks = BlockStateUtils.vanillaBlockStateCount(); + int[] newMappings = new int[blockStateMappings.length]; + int[] newMappingsMOD = new int[blockStateMappings.length]; + for (int i = 0; i < vanillaBlocks; i++) { + int mappedId = blockStateMappings[i]; + if (mappedId != -1) { + newMappings[i] = mappedId; + newMappingsMOD[i] = mappedId; + } else { + newMappings[i] = i; + newMappingsMOD[i] = i; } } - for (int i = 0; i < newMappingsMOD.length; i++) { - if (BlockStateUtils.isVanillaBlock(i)) { - newMappingsMOD[i] = newMappings[i]; + for (int i = vanillaBlocks; i < blockStateMappings.length; i++) { + int mappedId = blockStateMappings[i]; + if (mappedId != -1) { + newMappings[i] = mappedId; + } else { + newMappings[i] = stoneId; } + newMappingsMOD[i] = i; } this.blockStateRemapper = newMappings; this.modBlockStateRemapper = newMappingsMOD; - registerS2CGamePacketListener(new LevelChunkWithLightListener(newMappings, newMappingsMOD, registrySize, RegistryUtils.currentBiomeRegistrySize()), this.packetIds.clientboundLevelChunkWithLightPacket(), "ClientboundLevelChunkWithLightPacket"); + registerS2CGamePacketListener(new LevelChunkWithLightListener(newMappings, newMappingsMOD, newMappings.length, RegistryUtils.currentBiomeRegistrySize()), this.packetIds.clientboundLevelChunkWithLightPacket(), "ClientboundLevelChunkWithLightPacket"); registerS2CGamePacketListener(new SectionBlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundSectionBlocksUpdatePacket(), "ClientboundSectionBlocksUpdatePacket"); registerS2CGamePacketListener(new BlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundBlockUpdatePacket(), "ClientboundBlockUpdatePacket"); registerS2CGamePacketListener( diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientBlockStateSizePacket.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientBlockStateSizePacket.java index e2840c816..41adce8c7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientBlockStateSizePacket.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/payload/protocol/ClientBlockStateSizePacket.java @@ -36,5 +36,4 @@ public record ClientBlockStateSizePacket(int blockStateSize) implements ModPacke public void handle(NetWorkUser user) { user.setClientBlockList(new IntIdentityList(this.blockStateSize)); } - } 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 bbc030da9..0bbb93176 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 @@ -1220,6 +1220,10 @@ public final class CoreReflections { ReflectionUtils.getStaticMethod(clazz$MapColor, clazz$MapColor, int.class) ); + public static final Field field$MapColor$id = requireNonNull( + ReflectionUtils.getDeclaredField(clazz$MapColor, int.class, 1) + ); + public static final Class clazz$PushReaction = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "world.level.material.EnumPistonReaction", @@ -1292,7 +1296,6 @@ public final class CoreReflections { ReflectionUtils.getDeclaredField(clazz$BlockStateBase, clazz$MapColor, 0) ); - public static final Field field$BlockStateBase$instrument = requireNonNull( ReflectionUtils.getDeclaredField(clazz$BlockStateBase, clazz$NoteBlockInstrument, 0) ); @@ -3661,6 +3664,10 @@ public final class CoreReflections { ReflectionUtils.getDeclaredField(clazz$FireBlock, Object2IntMap.class, 0) ); + public static final Field field$FireBlock$burnOdds = requireNonNull( + ReflectionUtils.getDeclaredField(clazz$FireBlock, Object2IntMap.class, 1) + ); + public static final Class clazz$EnchantmentMenu = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "world.inventory.ContainerEnchantTable", 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 c08d6af2d..11557ee15 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 @@ -104,7 +104,7 @@ public class BukkitServerPlayer extends Player { private int resentSwingTick; // has fabric client mod or not private boolean hasClientMod = false; - private IntIdentityList blockList = new IntIdentityList(BlockStateUtils.vanillaStateSize()); + private IntIdentityList blockList = new IntIdentityList(BlockStateUtils.vanillaBlockStateCount()); // cache if player can break blocks private boolean clientSideCanBreak = true; // prevent AFK players from consuming too much CPU resource on predicting 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 a75f5808e..8c1f4c3d3 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 @@ -1,15 +1,10 @@ package net.momirealms.craftengine.bukkit.util; -import net.momirealms.craftengine.bukkit.block.BukkitBlockStateWrapper; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.reflection.ReflectionInitException; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; -import net.momirealms.craftengine.core.block.BlockSettings; -import net.momirealms.craftengine.core.block.BlockStateWrapper; -import net.momirealms.craftengine.core.block.DelegatingBlockState; -import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.Key; import org.bukkit.block.Block; @@ -18,30 +13,11 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.IdentityHashMap; import java.util.List; -import java.util.Map; import java.util.Optional; public final class BlockStateUtils { - public static final IdentityHashMap CLIENT_SIDE_NOTE_BLOCKS = new IdentityHashMap<>(); - private static int vanillaStateSize; - private static boolean hasInit; - public static Map IGNITE_ODDS; - - @SuppressWarnings("unchecked") - public static void init(int size) { - if (hasInit) { - throw new IllegalStateException("BlockStateUtils has already been initialized"); - } - vanillaStateSize = size; - try { - IGNITE_ODDS = (Map) CoreReflections.field$FireBlock$igniteOdds.get(MBlocks.FIRE); - } catch (ReflectiveOperationException e) { - throw new ReflectionInitException("Failed to initialize instance$FireBlock$igniteOdds", e); - } - hasInit = true; - } + private BlockStateUtils() {} public static BlockStateWrapper toBlockStateWrapper(BlockData blockData) { Object state = blockDataToBlockState(blockData); @@ -50,7 +26,7 @@ public final class BlockStateUtils { public static BlockStateWrapper toBlockStateWrapper(Object blockState) { int id = blockStateToId(blockState); - return new BukkitBlockStateWrapper(blockState, id); + return BlockRegistryMirror.byId(id); } public static boolean isCorrectTool(@NotNull ImmutableBlockState state, @Nullable Item itemInHand) { @@ -64,13 +40,13 @@ public final class BlockStateUtils { } @SuppressWarnings("unchecked") - public static List getAllVanillaBlockStates(Key block) { + public static List getPossibleBlockStates(Key block) { try { 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) { - throw new RuntimeException("Failed to get all block states for " + block, e); + throw new RuntimeException("Failed to get possible block states for " + block, e); } } @@ -116,10 +92,6 @@ public final class BlockStateUtils { return FastNMS.INSTANCE.method$BlockStateBase$isReplaceable(state); } - public static boolean isClientSideNoteBlock(Object state) { - return CLIENT_SIDE_NOTE_BLOCKS.containsKey(state); - } - public static boolean isVanillaBlock(Object state) { return !(state instanceof DelegatingBlockState); } @@ -129,11 +101,11 @@ public final class BlockStateUtils { } public static boolean isVanillaBlock(int id) { - return id >= 0 && id < vanillaStateSize; + return BukkitBlockManager.instance().isVanillaBlockState(id); } - public static int vanillaStateSize() { - return vanillaStateSize; + public static int vanillaBlockStateCount() { + return BukkitBlockManager.instance().vanillaBlockStateCount(); } public static Optional getOptionalCustomBlockState(Object state) { @@ -144,12 +116,11 @@ public final class BlockStateUtils { } } - public static boolean isBurnable(Object state) { - Object blockOwner = getBlockOwner(state); - return IGNITE_ODDS.getOrDefault(blockOwner, 0) > 0; - } - public static Object getBlockState(Block block) { return FastNMS.INSTANCE.method$BlockGetter$getBlockState(FastNMS.INSTANCE.field$CraftWorld$ServerLevel(block.getWorld()), LocationUtils.toBlockPos(block.getX(), block.getY(), block.getZ())); } + + public static boolean isBurnable(Object blockState) { + return BukkitBlockManager.instance().isBurnable(blockState); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java index b77fea1ba..1f00cd1dc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/NoteBlockChainUpdateUtils.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.bukkit.util; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; public final class NoteBlockChainUpdateUtils { @@ -11,7 +12,7 @@ public final class NoteBlockChainUpdateUtils { if (times-- < 0) return; Object relativePos = FastNMS.INSTANCE.method$BlockPos$relative(blockPos, direction); Object state = FastNMS.INSTANCE.method$BlockGetter$getBlockState(level, relativePos); - if (BlockStateUtils.isClientSideNoteBlock(state)) { + if (BukkitBlockManager.CLIENT_SIDE_NOTE_BLOCKS.contains(state)) { FastNMS.INSTANCE.method$ServerChunkCache$blockChanged(chunkSource, relativePos); noteBlockChainUpdate(level, chunkSource, direction, relativePos, times); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitExistingBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitExistingBlock.java index 38dd8db86..0c8d61650 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitExistingBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitExistingBlock.java @@ -64,7 +64,7 @@ public class BukkitExistingBlock implements ExistingBlock { @Override public @NotNull BlockStateWrapper blockState() { Object blockState = BlockStateUtils.getBlockState(this.block); - return BlockRegistryMirror.stateByRegistryId(BlockStateUtils.blockStateToId(blockState)); + return BlockRegistryMirror.byId(BlockStateUtils.blockStateToId(blockState)); } @Override diff --git a/common-files/src/main/resources/additional-real-blocks.yml b/common-files/src/main/resources/additional-real-blocks.yml deleted file mode 100644 index 6ca380ee7..000000000 --- a/common-files/src/main/resources/additional-real-blocks.yml +++ /dev/null @@ -1,91 +0,0 @@ -# This file will register an additional number of block states to the server, based on the mappings defined in mappings.yml. -# If you're unsure what this means, you can read the following explanation below. - -# Suppose you create a new type of leaf, but its appearance has only two states (waterlogged and normal). -# However, because of the defined properties such as distance, persistent, and waterlogged, it requires at least 2x2x7 = 28 different block states. -# By default, the plugin only registers the same number of block states as those defined in the mappings.yml file. -# Therefore, during actual configuration, you will notice that the internal IDs are insufficient -# (without configuring additional-real-block, one type of leaf can only provide 26 states, whereas creating a new leaf requires 28 states). -# The purpose of this file is to register additional block states with the server when starting it, ensuring the correct mapping between real blocks and the visual appearance of fake blocks on the server. - -# Some common questions: -# Q: Do I need to restart the server for the changes to take effect? -# A: Yes! Modifying the block registry while the server is running is extremely risky. -# Q: When do I need to configure this file? -# A: When the number of real block IDs is insufficient, but there are still available appearances. - -minecraft:oak_leaves: 112 -minecraft:oak_sapling: 1 -minecraft:birch_sapling: 1 -minecraft:spruce_sapling: 1 -minecraft:jungle_sapling: 1 -minecraft:dark_oak_sapling: 1 -minecraft:pale_oak_sapling: 1 -minecraft:acacia_sapling: 1 -minecraft:cherry_sapling: 1 -minecraft:anvil: 2 -minecraft:chipped_anvil: 2 -minecraft:damaged_anvil: 2 -minecraft:sugar_cane: 14 -minecraft:iron_trapdoor: 32 -minecraft:acacia_trapdoor: 32 -minecraft:oak_trapdoor: 32 -minecraft:spruce_trapdoor: 32 -minecraft:birch_trapdoor: 32 -minecraft:jungle_trapdoor: 32 -minecraft:dark_oak_trapdoor: 32 -minecraft:pale_oak_trapdoor: 32 -minecraft:mangrove_trapdoor: 32 -minecraft:cherry_trapdoor: 32 -minecraft:bamboo_trapdoor: 32 -minecraft:crimson_trapdoor: 32 -minecraft:warped_trapdoor: 32 -minecraft:copper_trapdoor: 32 -minecraft:exposed_copper_trapdoor: 32 -minecraft:weathered_copper_trapdoor: 32 -minecraft:oxidized_copper_trapdoor: 32 -minecraft:waxed_copper_trapdoor: 32 -minecraft:waxed_exposed_copper_trapdoor: 32 -minecraft:waxed_weathered_copper_trapdoor: 32 -minecraft:waxed_oxidized_copper_trapdoor: 32 -minecraft:iron_door: 32 -minecraft:acacia_door: 32 -minecraft:oak_door: 32 -minecraft:spruce_door: 32 -minecraft:birch_door: 32 -minecraft:jungle_door: 32 -minecraft:dark_oak_door: 32 -minecraft:pale_oak_door: 32 -minecraft:mangrove_door: 32 -minecraft:cherry_door: 32 -minecraft:bamboo_door: 32 -minecraft:crimson_door: 32 -minecraft:warped_door: 32 -minecraft:copper_door: 32 -minecraft:exposed_copper_door: 32 -minecraft:weathered_copper_door: 32 -minecraft:oxidized_copper_door: 32 -minecraft:waxed_copper_door: 32 -minecraft:waxed_exposed_copper_door: 32 -minecraft:waxed_weathered_copper_door: 32 -minecraft:waxed_oxidized_copper_door: 32 -minecraft:oak_fence_gate: 16 -minecraft:acacia_fence_gate: 16 -minecraft:spruce_fence_gate: 16 -minecraft:birch_fence_gate: 16 -minecraft:jungle_fence_gate: 16 -minecraft:dark_oak_fence_gate: 16 -minecraft:pale_oak_fence_gate: 16 -minecraft:mangrove_fence_gate: 16 -minecraft:cherry_fence_gate: 16 -minecraft:bamboo_fence_gate: 16 -minecraft:crimson_fence_gate: 16 -minecraft:warped_fence_gate: 16 -minecraft:barrier: 128 -minecraft:white_bed: 1 -minecraft:redstone_torch: 1 -minecraft:redstone_wall_torch: 4 -minecraft:pumpkin_stem: 8 -minecraft:attached_pumpkin_stem: 4 -minecraft:birch_button: 24 -minecraft:oak_fence: 32 \ No newline at end of file diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 22cbd0dad..6a773846c 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -139,7 +139,7 @@ resource-pack: item: # Make custom-model-data and item-model clientside by default - client-bound-model: false + client-bound-model: true # Add a tag on custom name and lore non-italic-tag: false # Determines when to trigger the item updater diff --git a/common-files/src/main/resources/mappings.yml b/common-files/src/main/resources/mappings.yml deleted file mode 100644 index d3f9f58f2..000000000 --- a/common-files/src/main/resources/mappings.yml +++ /dev/null @@ -1,4452 +0,0 @@ -# This is one of the plugin's core settings - it basically controls how many block states you can use in your config files. -# Heads up: if you edit this, you'll need to restart the server for changes to take effect. -# Below is the default setup - feel free to add or remove stuff as needed. - -#### Anvil #### -# An anvil has four possible orientations, but the east-west and north-south orientations look exactly the same. -minecraft:anvil[facing=north]: minecraft:anvil[facing=south] -minecraft:anvil[facing=east]: minecraft:anvil[facing=west] -minecraft:chipped_anvil[facing=north]: minecraft:chipped_anvil[facing=south] -minecraft:chipped_anvil[facing=east]: minecraft:chipped_anvil[facing=west] -minecraft:damaged_anvil[facing=north]: minecraft:damaged_anvil[facing=south] -minecraft:damaged_anvil[facing=east]: minecraft:damaged_anvil[facing=west] - -#### Sapling #### -# Every sapling has two stages, 0 and 1, but they look exactly the same. -minecraft:oak_sapling[stage=1]: minecraft:oak_sapling[stage=0] -minecraft:birch_sapling[stage=1]: minecraft:birch_sapling[stage=0] -minecraft:spruce_sapling[stage=1]: minecraft:spruce_sapling[stage=0] -minecraft:jungle_sapling[stage=1]: minecraft:jungle_sapling[stage=0] -minecraft:dark_oak_sapling[stage=1]: minecraft:dark_oak_sapling[stage=0] -minecraft:acacia_sapling[stage=1]: minecraft:acacia_sapling[stage=0] -minecraft:cherry_sapling[stage=1]: minecraft:cherry_sapling[stage=0] -$$>=1.21.4#sapling: - minecraft:pale_oak_sapling[stage=1]: minecraft:pale_oak_sapling[stage=0] - -#### Sculk Sensor #### -# The Sculk Sensor's hitbox is exactly half a block. Plus, its appearance only changes based on the sculk_sensor_phase, -# not the power level. That means we can repurpose the extra states to make bottom-half slabs -minecraft:sculk_sensor[power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:sculk_sensor[power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:sculk_sensor[power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:sculk_sensor[power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:sculk_sensor[power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:sculk_sensor[power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:sculk_sensor[power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] - -#### Calibrated Sculk Sensor #### -# Just like the regular Sculk Sensor, but the Calibrated Sculk Sensor has directional facing - which gives us way more usable states to play with -minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] -minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] -minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] - -#### Mushroom #### -# Most people probably don't mind that mushroom blocks look the same on all six sides. So that means each type can free up like, 63 different states we could use for other stuff -minecraft:mushroom_stem[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:brown_mushroom_block[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] -minecraft:red_mushroom_block[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] - -#### Kelp #### -# 'kelp' here means specifically the top block of the kelp plant. Great for making aquatic crops. -minecraft:kelp[age=1]: minecraft:kelp[age=0] -minecraft:kelp[age=2]: minecraft:kelp[age=0] -minecraft:kelp[age=3]: minecraft:kelp[age=0] -minecraft:kelp[age=4]: minecraft:kelp[age=0] -minecraft:kelp[age=5]: minecraft:kelp[age=0] -minecraft:kelp[age=6]: minecraft:kelp[age=0] -minecraft:kelp[age=7]: minecraft:kelp[age=0] -minecraft:kelp[age=8]: minecraft:kelp[age=0] -minecraft:kelp[age=9]: minecraft:kelp[age=0] -minecraft:kelp[age=10]: minecraft:kelp[age=0] -minecraft:kelp[age=11]: minecraft:kelp[age=0] -minecraft:kelp[age=12]: minecraft:kelp[age=0] -minecraft:kelp[age=13]: minecraft:kelp[age=0] -minecraft:kelp[age=14]: minecraft:kelp[age=0] -minecraft:kelp[age=15]: minecraft:kelp[age=0] -minecraft:kelp[age=16]: minecraft:kelp[age=0] -minecraft:kelp[age=17]: minecraft:kelp[age=0] -minecraft:kelp[age=18]: minecraft:kelp[age=0] -minecraft:kelp[age=19]: minecraft:kelp[age=0] -minecraft:kelp[age=20]: minecraft:kelp[age=0] -minecraft:kelp[age=21]: minecraft:kelp[age=0] -minecraft:kelp[age=22]: minecraft:kelp[age=0] -minecraft:kelp[age=23]: minecraft:kelp[age=0] -minecraft:kelp[age=24]: minecraft:kelp[age=0] -minecraft:kelp[age=25]: minecraft:kelp[age=0] - -#### Vines #### -# Unless you tweak the vine's block tag, the client will always think it's climbable. -# Since vines look identical at different growth stages, we can repurpose those extra states to make custom blocks like ropes. -minecraft:weeping_vines[age=1]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=2]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=3]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=4]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=5]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=6]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=7]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=8]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=9]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=10]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=11]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=12]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=13]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=14]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=15]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=16]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=17]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=18]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=19]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=20]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=21]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=22]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=23]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=24]: minecraft:weeping_vines[age=0] -minecraft:weeping_vines[age=25]: minecraft:weeping_vines[age=0] -minecraft:twisting_vines[age=1]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=2]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=3]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=4]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=5]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=6]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=7]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=8]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=9]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=10]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=11]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=12]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=13]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=14]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=15]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=16]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=17]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=18]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=19]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=20]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=21]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=22]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=23]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=24]: minecraft:twisting_vines[age=0] -minecraft:twisting_vines[age=25]: minecraft:twisting_vines[age=0] -minecraft:cave_vines[age=1,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=2,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=3,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=4,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=5,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=6,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=7,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=8,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=9,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=10,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=11,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=12,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=13,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=14,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=15,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=16,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=17,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=18,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=19,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=20,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=21,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=22,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=23,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=24,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=25,berries=false]: minecraft:cave_vines[age=0,berries=false] -minecraft:cave_vines[age=1,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=2,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=3,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=4,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=5,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=6,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=7,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=8,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=9,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=10,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=11,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=12,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=13,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=14,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=15,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=16,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=17,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=18,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=19,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=20,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=21,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=22,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=23,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=24,berries=true]: minecraft:cave_vines[age=0,berries=true] -minecraft:cave_vines[age=25,berries=true]: minecraft:cave_vines[age=0,berries=true] - -#### SugarCane #### -# Sugar cane looks exactly the same no matter its growth stage. Plus, it's got this perfect hitbox that makes it awesome for taller plants -minecraft:sugar_cane[age=1]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=2]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=3]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=4]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=5]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=6]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=7]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=8]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=9]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=10]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=11]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=12]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=13]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=14]: minecraft:sugar_cane[age=0] -minecraft:sugar_cane[age=15]: minecraft:sugar_cane[age=0] - -#### Cactus #### -# Cactus looks the same at all growth stages.Its hitbox is 14x14x15, making it perfect for creating blocks that are just slightly smaller than full-size -minecraft:cactus[age=1]: minecraft:cactus[age=0] -minecraft:cactus[age=2]: minecraft:cactus[age=0] -minecraft:cactus[age=3]: minecraft:cactus[age=0] -minecraft:cactus[age=4]: minecraft:cactus[age=0] -minecraft:cactus[age=5]: minecraft:cactus[age=0] -minecraft:cactus[age=6]: minecraft:cactus[age=0] -minecraft:cactus[age=7]: minecraft:cactus[age=0] -minecraft:cactus[age=8]: minecraft:cactus[age=0] -minecraft:cactus[age=9]: minecraft:cactus[age=0] -minecraft:cactus[age=10]: minecraft:cactus[age=0] -minecraft:cactus[age=11]: minecraft:cactus[age=0] -minecraft:cactus[age=12]: minecraft:cactus[age=0] -minecraft:cactus[age=13]: minecraft:cactus[age=0] -minecraft:cactus[age=14]: minecraft:cactus[age=0] -minecraft:cactus[age=15]: minecraft:cactus[age=0] - -#### Leaves #### -# The 'distance' and 'persistent' properties are used under the hood to optimize how leaves decay, but visually? They look exactly the same. -# These are some of the few block types that actually support transparent textures. -minecraft:oak_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:oak_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:oak_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:acacia_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:acacia_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:jungle_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:jungle_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:birch_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:birch_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:mangrove_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:mangrove_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:cherry_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:cherry_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:dark_oak_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:dark_oak_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:azalea_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:azalea_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:flowering_azalea_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:flowering_azalea_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] -minecraft:spruce_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] -minecraft:spruce_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] - -$$>=1.21.4#leaves: - minecraft:pale_oak_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] - minecraft:pale_oak_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - minecraft:pale_oak_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] - -#### Tripwire #### -# Tripwires actually have 128 different states, but we're keeping just two of them to match vanilla's visual styles. -# Honestly, as long as the tripwire works properly, most players won't even mind what it looks like. -# Tripwire hitboxes aren't all the same - the triggered ones are way shorter. -minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] -minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] - -#### Note Block #### -# This block has the most unused states in Minecraft, but the client always thinks it's interactive. -# Plus, there's some visual glitches when the client try predicting instrument changes. -# We've kept a full set of note settings by default - that way it plays nice with resource packs that show notes -minecraft:note_block[instrument=hat,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=hat,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=hat,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=hat,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=hat,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=hat,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=hat,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=hat,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=hat,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=hat,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=hat,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=hat,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=hat,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=hat,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=hat,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=hat,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=hat,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=hat,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=hat,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=hat,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=hat,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=hat,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=hat,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=hat,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=hat,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=hat,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=hat,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=hat,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=hat,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=hat,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=hat,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=hat,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=hat,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=hat,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=hat,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=hat,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=hat,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=hat,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=hat,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=hat,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=hat,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=hat,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=hat,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=hat,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=hat,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=hat,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=hat,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=hat,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=hat,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=hat,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=basedrum,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=basedrum,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=basedrum,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=basedrum,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=basedrum,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=basedrum,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=basedrum,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=basedrum,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=basedrum,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=basedrum,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=basedrum,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=basedrum,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=basedrum,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=basedrum,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=basedrum,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=basedrum,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=basedrum,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=basedrum,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=basedrum,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=basedrum,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=basedrum,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=basedrum,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=basedrum,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=basedrum,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=basedrum,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=basedrum,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=basedrum,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=basedrum,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=basedrum,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=basedrum,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=basedrum,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=basedrum,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=basedrum,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=basedrum,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=basedrum,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=basedrum,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=basedrum,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=basedrum,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=basedrum,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=basedrum,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=basedrum,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=basedrum,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=basedrum,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=basedrum,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=basedrum,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=basedrum,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=basedrum,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=basedrum,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=basedrum,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=basedrum,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=snare,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=snare,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=snare,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=snare,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=snare,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=snare,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=snare,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=snare,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=snare,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=snare,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=snare,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=snare,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=snare,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=snare,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=snare,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=snare,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=snare,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=snare,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=snare,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=snare,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=snare,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=snare,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=snare,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=snare,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=snare,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=snare,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=snare,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=snare,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=snare,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=snare,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=snare,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=snare,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=snare,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=snare,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=snare,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=snare,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=snare,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=snare,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=snare,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=snare,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=snare,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=snare,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=snare,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=snare,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=snare,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=snare,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=snare,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=snare,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=snare,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=snare,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=bass,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=bass,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=bass,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=bass,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=bass,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=bass,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=bass,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=bass,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=bass,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=bass,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=bass,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=bass,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=bass,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=bass,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=bass,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=bass,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=bass,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=bass,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=bass,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=bass,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=bass,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=bass,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=bass,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=bass,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=bass,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=bass,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=bass,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=bass,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=bass,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=bass,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=bass,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=bass,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=bass,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=bass,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=bass,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=bass,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=bass,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=bass,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=bass,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=bass,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=bass,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=bass,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=bass,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=bass,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=bass,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=bass,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=bass,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=bass,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=bass,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=bass,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=flute,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=flute,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=flute,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=flute,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=flute,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=flute,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=flute,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=flute,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=flute,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=flute,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=flute,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=flute,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=flute,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=flute,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=flute,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=flute,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=flute,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=flute,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=flute,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=flute,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=flute,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=flute,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=flute,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=flute,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=flute,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=flute,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=flute,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=flute,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=flute,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=flute,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=flute,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=flute,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=flute,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=flute,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=flute,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=flute,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=flute,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=flute,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=flute,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=flute,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=flute,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=flute,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=flute,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=flute,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=flute,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=flute,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=flute,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=flute,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=flute,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=flute,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=bell,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=bell,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=bell,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=bell,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=bell,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=bell,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=bell,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=bell,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=bell,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=bell,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=bell,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=bell,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=bell,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=bell,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=bell,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=bell,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=bell,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=bell,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=bell,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=bell,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=bell,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=bell,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=bell,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=bell,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=bell,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=bell,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=bell,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=bell,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=bell,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=bell,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=bell,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=bell,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=bell,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=bell,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=bell,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=bell,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=bell,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=bell,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=bell,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=bell,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=bell,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=bell,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=bell,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=bell,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=bell,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=bell,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=bell,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=bell,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=bell,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=bell,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=guitar,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=guitar,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=guitar,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=guitar,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=guitar,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=guitar,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=guitar,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=guitar,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=guitar,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=guitar,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=guitar,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=guitar,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=guitar,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=guitar,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=guitar,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=guitar,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=guitar,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=guitar,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=guitar,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=guitar,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=guitar,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=guitar,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=guitar,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=guitar,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=guitar,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=guitar,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=guitar,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=guitar,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=guitar,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=guitar,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=guitar,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=guitar,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=guitar,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=guitar,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=guitar,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=guitar,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=guitar,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=guitar,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=guitar,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=guitar,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=guitar,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=guitar,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=guitar,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=guitar,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=guitar,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=guitar,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=guitar,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=guitar,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=guitar,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=guitar,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=chime,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=chime,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=chime,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=chime,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=chime,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=chime,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=chime,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=chime,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=chime,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=chime,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=chime,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=chime,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=chime,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=chime,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=chime,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=chime,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=chime,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=chime,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=chime,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=chime,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=chime,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=chime,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=chime,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=chime,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=chime,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=chime,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=chime,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=chime,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=chime,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=chime,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=chime,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=chime,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=chime,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=chime,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=chime,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=chime,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=chime,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=chime,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=chime,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=chime,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=chime,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=chime,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=chime,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=chime,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=chime,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=chime,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=chime,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=chime,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=chime,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=chime,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=xylophone,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=xylophone,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=xylophone,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=xylophone,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=xylophone,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=xylophone,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=xylophone,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=xylophone,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=xylophone,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=xylophone,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=xylophone,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=xylophone,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=xylophone,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=xylophone,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=xylophone,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=xylophone,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=xylophone,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=xylophone,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=xylophone,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=xylophone,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=xylophone,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=xylophone,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=xylophone,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=xylophone,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=xylophone,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=xylophone,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=xylophone,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=xylophone,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=xylophone,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=xylophone,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=xylophone,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=xylophone,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=xylophone,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=xylophone,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=xylophone,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=xylophone,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=xylophone,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=xylophone,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=xylophone,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=xylophone,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=xylophone,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=xylophone,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=xylophone,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=xylophone,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=xylophone,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=xylophone,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=xylophone,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=xylophone,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=xylophone,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=xylophone,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=iron_xylophone,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=iron_xylophone,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=cow_bell,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=cow_bell,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=cow_bell,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=cow_bell,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=cow_bell,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=cow_bell,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=cow_bell,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=cow_bell,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=cow_bell,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=cow_bell,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=cow_bell,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=cow_bell,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=cow_bell,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=cow_bell,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=cow_bell,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=cow_bell,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=cow_bell,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=cow_bell,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=cow_bell,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=cow_bell,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=cow_bell,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=cow_bell,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=cow_bell,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=cow_bell,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=cow_bell,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=cow_bell,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=cow_bell,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=cow_bell,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=cow_bell,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=cow_bell,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=cow_bell,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=cow_bell,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=cow_bell,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=cow_bell,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=cow_bell,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=cow_bell,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=cow_bell,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=cow_bell,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=cow_bell,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=cow_bell,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=cow_bell,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=cow_bell,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=cow_bell,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=cow_bell,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=cow_bell,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=cow_bell,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=cow_bell,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=cow_bell,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=cow_bell,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=cow_bell,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=didgeridoo,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=didgeridoo,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=didgeridoo,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=didgeridoo,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=didgeridoo,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=didgeridoo,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=didgeridoo,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=didgeridoo,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=didgeridoo,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=didgeridoo,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=didgeridoo,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=didgeridoo,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=didgeridoo,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=didgeridoo,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=didgeridoo,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=didgeridoo,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=didgeridoo,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=didgeridoo,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=didgeridoo,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=didgeridoo,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=didgeridoo,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=didgeridoo,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=didgeridoo,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=didgeridoo,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=didgeridoo,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=didgeridoo,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=didgeridoo,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=didgeridoo,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=didgeridoo,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=didgeridoo,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=didgeridoo,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=didgeridoo,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=didgeridoo,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=didgeridoo,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=didgeridoo,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=didgeridoo,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=didgeridoo,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=didgeridoo,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=didgeridoo,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=didgeridoo,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=didgeridoo,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=didgeridoo,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=didgeridoo,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=didgeridoo,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=didgeridoo,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=didgeridoo,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=didgeridoo,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=didgeridoo,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=didgeridoo,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=didgeridoo,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=bit,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=bit,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=bit,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=bit,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=bit,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=bit,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=bit,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=bit,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=bit,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=bit,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=bit,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=bit,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=bit,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=bit,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=bit,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=bit,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=bit,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=bit,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=bit,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=bit,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=bit,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=bit,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=bit,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=bit,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=bit,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=bit,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=bit,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=bit,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=bit,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=bit,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=bit,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=bit,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=bit,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=bit,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=bit,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=bit,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=bit,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=bit,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=bit,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=bit,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=bit,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=bit,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=bit,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=bit,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=bit,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=bit,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=bit,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=bit,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=bit,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=bit,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=banjo,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=banjo,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=banjo,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=banjo,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=banjo,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=banjo,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=banjo,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=banjo,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=banjo,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=banjo,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=banjo,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=banjo,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=banjo,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=banjo,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=banjo,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=banjo,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=banjo,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=banjo,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=banjo,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=banjo,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=banjo,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=banjo,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=banjo,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=banjo,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=banjo,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=banjo,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=banjo,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=banjo,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=banjo,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=banjo,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=banjo,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=banjo,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=banjo,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=banjo,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=banjo,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=banjo,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=banjo,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=banjo,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=banjo,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=banjo,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=banjo,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=banjo,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=banjo,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=banjo,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=banjo,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=banjo,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=banjo,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=banjo,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=banjo,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=banjo,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=pling,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=pling,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=pling,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=pling,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=pling,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=pling,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=pling,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=pling,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=pling,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=pling,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=pling,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=pling,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=pling,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=pling,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=pling,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=pling,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=pling,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=pling,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=pling,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=pling,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=pling,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=pling,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=pling,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=pling,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=pling,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=pling,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=pling,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=pling,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=pling,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=pling,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=pling,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=pling,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=pling,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=pling,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=pling,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=pling,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=pling,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=pling,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=pling,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=pling,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=pling,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=pling,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=pling,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=pling,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=pling,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=pling,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=pling,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=pling,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=pling,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=pling,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=zombie,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=zombie,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=zombie,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=zombie,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=zombie,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=zombie,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=zombie,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=zombie,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=zombie,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=zombie,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=zombie,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=zombie,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=zombie,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=zombie,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=zombie,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=zombie,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=zombie,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=zombie,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=zombie,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=zombie,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=zombie,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=zombie,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=zombie,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=zombie,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=zombie,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=zombie,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=zombie,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=zombie,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=zombie,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=zombie,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=zombie,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=zombie,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=zombie,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=zombie,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=zombie,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=zombie,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=zombie,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=zombie,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=zombie,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=zombie,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=zombie,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=zombie,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=zombie,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=zombie,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=zombie,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=zombie,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=zombie,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=zombie,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=zombie,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=zombie,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=skeleton,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=skeleton,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=skeleton,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=skeleton,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=skeleton,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=skeleton,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=skeleton,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=skeleton,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=skeleton,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=skeleton,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=skeleton,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=skeleton,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=skeleton,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=skeleton,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=skeleton,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=skeleton,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=skeleton,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=skeleton,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=skeleton,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=skeleton,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=skeleton,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=skeleton,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=skeleton,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=skeleton,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=skeleton,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=skeleton,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=skeleton,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=skeleton,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=skeleton,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=skeleton,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=skeleton,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=skeleton,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=skeleton,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=skeleton,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=skeleton,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=skeleton,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=skeleton,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=skeleton,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=skeleton,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=skeleton,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=skeleton,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=skeleton,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=skeleton,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=skeleton,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=skeleton,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=skeleton,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=skeleton,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=skeleton,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=skeleton,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=skeleton,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=creeper,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=creeper,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=creeper,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=creeper,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=creeper,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=creeper,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=creeper,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=creeper,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=creeper,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=creeper,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=creeper,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=creeper,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=creeper,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=creeper,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=creeper,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=creeper,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=creeper,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=creeper,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=creeper,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=creeper,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=creeper,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=creeper,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=creeper,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=creeper,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=creeper,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=creeper,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=creeper,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=creeper,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=creeper,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=creeper,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=creeper,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=creeper,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=creeper,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=creeper,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=creeper,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=creeper,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=creeper,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=creeper,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=creeper,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=creeper,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=creeper,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=creeper,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=creeper,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=creeper,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=creeper,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=creeper,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=creeper,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=creeper,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=creeper,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=creeper,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=dragon,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=dragon,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=dragon,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=dragon,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=dragon,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=dragon,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=dragon,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=dragon,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=dragon,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=dragon,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=dragon,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=dragon,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=dragon,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=dragon,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=dragon,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=dragon,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=dragon,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=dragon,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=dragon,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=dragon,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=dragon,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=dragon,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=dragon,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=dragon,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=dragon,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=dragon,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=dragon,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=dragon,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=dragon,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=dragon,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=dragon,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=dragon,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=dragon,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=dragon,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=dragon,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=dragon,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=dragon,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=dragon,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=dragon,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=dragon,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=dragon,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=dragon,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=dragon,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=dragon,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=dragon,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=dragon,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=dragon,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=dragon,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=dragon,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=dragon,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=wither_skeleton,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=wither_skeleton,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=piglin,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=piglin,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=piglin,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=piglin,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=piglin,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=piglin,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=piglin,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=piglin,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=piglin,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=piglin,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=piglin,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=piglin,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=piglin,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=piglin,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=piglin,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=piglin,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=piglin,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=piglin,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=piglin,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=piglin,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=piglin,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=piglin,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=piglin,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=piglin,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=piglin,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=piglin,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=piglin,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=piglin,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=piglin,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=piglin,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=piglin,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=piglin,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=piglin,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=piglin,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=piglin,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=piglin,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=piglin,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=piglin,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=piglin,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=piglin,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=piglin,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=piglin,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=piglin,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=piglin,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=piglin,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=piglin,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=piglin,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=piglin,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=piglin,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=piglin,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] -minecraft:note_block[instrument=custom_head,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] -minecraft:note_block[instrument=custom_head,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] -minecraft:note_block[instrument=custom_head,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] -minecraft:note_block[instrument=custom_head,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] -minecraft:note_block[instrument=custom_head,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] -minecraft:note_block[instrument=custom_head,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] -minecraft:note_block[instrument=custom_head,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] -minecraft:note_block[instrument=custom_head,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] -minecraft:note_block[instrument=custom_head,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] -minecraft:note_block[instrument=custom_head,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] -minecraft:note_block[instrument=custom_head,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] -minecraft:note_block[instrument=custom_head,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] -minecraft:note_block[instrument=custom_head,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] -minecraft:note_block[instrument=custom_head,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] -minecraft:note_block[instrument=custom_head,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] -minecraft:note_block[instrument=custom_head,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] -minecraft:note_block[instrument=custom_head,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] -minecraft:note_block[instrument=custom_head,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] -minecraft:note_block[instrument=custom_head,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] -minecraft:note_block[instrument=custom_head,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] -minecraft:note_block[instrument=custom_head,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] -minecraft:note_block[instrument=custom_head,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] -minecraft:note_block[instrument=custom_head,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] -minecraft:note_block[instrument=custom_head,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] -minecraft:note_block[instrument=custom_head,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] -minecraft:note_block[instrument=custom_head,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] -minecraft:note_block[instrument=custom_head,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] -minecraft:note_block[instrument=custom_head,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] -minecraft:note_block[instrument=custom_head,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] -minecraft:note_block[instrument=custom_head,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] -minecraft:note_block[instrument=custom_head,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] -minecraft:note_block[instrument=custom_head,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] -minecraft:note_block[instrument=custom_head,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] -minecraft:note_block[instrument=custom_head,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] -minecraft:note_block[instrument=custom_head,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] -minecraft:note_block[instrument=custom_head,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] -minecraft:note_block[instrument=custom_head,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] -minecraft:note_block[instrument=custom_head,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] -minecraft:note_block[instrument=custom_head,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] -minecraft:note_block[instrument=custom_head,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] -minecraft:note_block[instrument=custom_head,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] -minecraft:note_block[instrument=custom_head,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] -minecraft:note_block[instrument=custom_head,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] -minecraft:note_block[instrument=custom_head,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] -minecraft:note_block[instrument=custom_head,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] -minecraft:note_block[instrument=custom_head,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] -minecraft:note_block[instrument=custom_head,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] -minecraft:note_block[instrument=custom_head,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] -minecraft:note_block[instrument=custom_head,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] -minecraft:note_block[instrument=custom_head,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] - -#### Trapdoor #### -# Trapdoors look identical whether they're powered or not - which means we can double our trapdoors by using both states -minecraft:iron_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:iron_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:iron_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:acacia_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:acacia_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:spruce_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:spruce_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:birch_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:birch_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:jungle_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:jungle_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:mangrove_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:mangrove_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:cherry_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:cherry_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:bamboo_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:bamboo_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:crimson_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:crimson_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] -minecraft:warped_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] -minecraft:warped_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - -$$>=1.20.3#trapdoor: - minecraft:copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - # Fun fact: copper blocks look the same whether waxed or not. - # We're playing it safe with the default setup - keeping vanilla's waxed states recognizable. - # But you can always change it to convert waxed blocks back to regular ones. - minecraft:waxed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - -$$>=1.21.4#trapdoor: - minecraft:pale_oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] - minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] - minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] - -#### Door #### -# A door look exactly the same whether it's powered on or off, just like how a trapdoor works -minecraft:oak_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:oak_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:oak_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:oak_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:oak_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:spruce_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:spruce_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:spruce_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:spruce_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:spruce_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:spruce_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:spruce_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:spruce_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:spruce_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:spruce_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:spruce_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:spruce_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:spruce_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:spruce_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:spruce_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:spruce_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:spruce_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:spruce_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:spruce_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:spruce_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:spruce_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:spruce_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:spruce_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:spruce_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:spruce_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:spruce_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:spruce_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:spruce_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:spruce_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:spruce_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:spruce_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:spruce_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:birch_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:birch_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:birch_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:birch_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:birch_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:birch_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:birch_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:birch_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:birch_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:birch_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:birch_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:birch_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:birch_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:birch_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:birch_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:birch_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:birch_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:birch_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:birch_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:birch_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:birch_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:birch_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:birch_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:birch_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:birch_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:birch_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:birch_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:birch_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:birch_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:birch_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:birch_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:birch_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:jungle_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:jungle_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:jungle_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:jungle_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:jungle_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:jungle_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:jungle_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:jungle_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:jungle_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:jungle_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:jungle_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:jungle_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:jungle_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:jungle_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:jungle_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:jungle_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:jungle_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:jungle_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:jungle_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:jungle_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:jungle_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:jungle_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:jungle_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:jungle_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:jungle_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:jungle_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:jungle_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:jungle_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:jungle_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:jungle_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:jungle_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:jungle_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:acacia_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:acacia_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:acacia_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:acacia_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:acacia_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:acacia_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:acacia_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:acacia_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:acacia_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:acacia_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:acacia_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:acacia_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:acacia_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:acacia_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:acacia_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:acacia_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:acacia_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:acacia_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:acacia_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:acacia_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:acacia_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:acacia_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:acacia_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:acacia_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:acacia_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:acacia_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:acacia_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:acacia_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:acacia_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:acacia_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:acacia_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:acacia_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:dark_oak_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:dark_oak_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:dark_oak_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:dark_oak_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:dark_oak_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:dark_oak_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:dark_oak_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:dark_oak_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:dark_oak_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:dark_oak_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:dark_oak_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:dark_oak_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:dark_oak_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:dark_oak_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:dark_oak_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:dark_oak_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:dark_oak_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:dark_oak_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:mangrove_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:mangrove_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:mangrove_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:mangrove_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:mangrove_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:mangrove_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:mangrove_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:mangrove_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:mangrove_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:mangrove_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:mangrove_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:mangrove_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:mangrove_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:mangrove_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:mangrove_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:mangrove_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:mangrove_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:mangrove_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:mangrove_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:mangrove_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:mangrove_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:mangrove_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:mangrove_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:mangrove_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:mangrove_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:mangrove_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:mangrove_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:mangrove_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:mangrove_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:mangrove_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:mangrove_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:mangrove_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:cherry_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:cherry_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:cherry_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:cherry_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:cherry_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:cherry_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:cherry_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:cherry_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:cherry_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:cherry_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:cherry_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:cherry_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:cherry_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:cherry_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:cherry_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:cherry_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:cherry_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:cherry_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:cherry_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:cherry_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:cherry_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:cherry_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:cherry_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:cherry_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:cherry_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:cherry_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:cherry_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:cherry_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:cherry_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:cherry_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:cherry_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:cherry_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:bamboo_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:bamboo_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:bamboo_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:bamboo_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:bamboo_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:bamboo_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:bamboo_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:bamboo_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:bamboo_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:bamboo_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:bamboo_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:bamboo_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:bamboo_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:bamboo_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:bamboo_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:bamboo_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:bamboo_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:bamboo_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:bamboo_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:bamboo_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:bamboo_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:bamboo_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:bamboo_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:bamboo_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:bamboo_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:bamboo_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:bamboo_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:bamboo_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:bamboo_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:bamboo_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:bamboo_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:bamboo_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:crimson_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:crimson_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:crimson_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:crimson_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:crimson_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:crimson_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:crimson_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:crimson_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:crimson_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:crimson_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:crimson_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:crimson_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:crimson_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:crimson_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:crimson_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:crimson_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:crimson_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:crimson_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:crimson_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:crimson_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:crimson_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:crimson_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:crimson_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:crimson_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:crimson_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:crimson_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:crimson_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:crimson_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:crimson_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:crimson_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:crimson_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:crimson_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:warped_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:warped_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:warped_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:warped_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:warped_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:warped_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:warped_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:warped_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:warped_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:warped_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:warped_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:warped_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:warped_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:warped_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:warped_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:warped_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:warped_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:warped_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:warped_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:warped_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:warped_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:warped_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:warped_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:warped_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:warped_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:warped_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:warped_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:warped_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:warped_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:warped_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:warped_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:warped_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=west,half=upper,hinge=right,open=true,powered=false] -minecraft:iron_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=east,half=lower,hinge=left,open=false,powered=false] -minecraft:iron_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=east,half=lower,hinge=right,open=false,powered=false] -minecraft:iron_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=east,half=upper,hinge=left,open=false,powered=false] -minecraft:iron_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=east,half=upper,hinge=right,open=false,powered=false] -minecraft:iron_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=east,half=lower,hinge=left,open=true,powered=false] -minecraft:iron_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=east,half=lower,hinge=right,open=true,powered=false] -minecraft:iron_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=east,half=upper,hinge=left,open=true,powered=false] -minecraft:iron_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=east,half=upper,hinge=right,open=true,powered=false] -minecraft:iron_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=north,half=lower,hinge=left,open=false,powered=false] -minecraft:iron_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=north,half=lower,hinge=right,open=false,powered=false] -minecraft:iron_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=north,half=upper,hinge=left,open=false,powered=false] -minecraft:iron_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=north,half=upper,hinge=right,open=false,powered=false] -minecraft:iron_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=north,half=lower,hinge=left,open=true,powered=false] -minecraft:iron_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=north,half=lower,hinge=right,open=true,powered=false] -minecraft:iron_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=north,half=upper,hinge=left,open=true,powered=false] -minecraft:iron_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=north,half=upper,hinge=right,open=true,powered=false] -minecraft:iron_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=south,half=lower,hinge=left,open=false,powered=false] -minecraft:iron_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=south,half=lower,hinge=right,open=false,powered=false] -minecraft:iron_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=south,half=upper,hinge=left,open=false,powered=false] -minecraft:iron_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=south,half=upper,hinge=right,open=false,powered=false] -minecraft:iron_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=south,half=lower,hinge=left,open=true,powered=false] -minecraft:iron_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=south,half=lower,hinge=right,open=true,powered=false] -minecraft:iron_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=south,half=upper,hinge=left,open=true,powered=false] -minecraft:iron_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=south,half=upper,hinge=right,open=true,powered=false] -minecraft:iron_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=west,half=lower,hinge=left,open=false,powered=false] -minecraft:iron_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=west,half=lower,hinge=right,open=false,powered=false] -minecraft:iron_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=west,half=upper,hinge=left,open=false,powered=false] -minecraft:iron_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=west,half=upper,hinge=right,open=false,powered=false] -minecraft:iron_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=west,half=lower,hinge=left,open=true,powered=false] -minecraft:iron_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=west,half=lower,hinge=right,open=true,powered=false] -minecraft:iron_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=west,half=upper,hinge=left,open=true,powered=false] -minecraft:iron_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=west,half=upper,hinge=right,open=true,powered=false] - -$$>=1.20.3#door: - minecraft:copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] - minecraft:copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] - minecraft:copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] - minecraft:copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] - minecraft:copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] - minecraft:copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] - minecraft:copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] - minecraft:copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] - minecraft:copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] - minecraft:copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] - minecraft:copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] - minecraft:copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] - minecraft:copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] - minecraft:copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] - minecraft:copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] - minecraft:copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] - minecraft:copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] - minecraft:copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] - minecraft:copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] - minecraft:copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] - minecraft:copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] - minecraft:copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] - minecraft:copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] - minecraft:copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] - minecraft:copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] - minecraft:copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] - minecraft:copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] - minecraft:copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] - minecraft:copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] - minecraft:copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] - minecraft:copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] - minecraft:copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] - minecraft:exposed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] - minecraft:exposed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] - minecraft:exposed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] - minecraft:exposed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] - minecraft:exposed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] - minecraft:exposed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] - minecraft:exposed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] - minecraft:exposed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] - minecraft:exposed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] - minecraft:exposed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] - minecraft:exposed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] - minecraft:exposed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] - minecraft:exposed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] - minecraft:exposed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] - minecraft:exposed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] - minecraft:exposed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] - minecraft:exposed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] - minecraft:exposed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] - minecraft:exposed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] - minecraft:exposed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] - minecraft:exposed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] - minecraft:exposed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] - minecraft:exposed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] - minecraft:exposed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] - minecraft:exposed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] - minecraft:exposed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] - minecraft:exposed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] - minecraft:exposed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] - minecraft:exposed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] - minecraft:exposed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] - minecraft:exposed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] - minecraft:exposed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] - minecraft:weathered_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] - minecraft:weathered_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] - minecraft:weathered_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] - minecraft:weathered_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] - minecraft:weathered_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] - minecraft:weathered_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] - minecraft:weathered_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] - minecraft:weathered_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] - minecraft:weathered_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] - minecraft:weathered_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] - minecraft:weathered_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] - minecraft:weathered_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] - minecraft:weathered_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] - minecraft:weathered_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] - minecraft:weathered_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] - minecraft:weathered_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] - minecraft:weathered_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] - minecraft:weathered_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] - minecraft:weathered_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] - minecraft:weathered_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] - minecraft:weathered_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] - minecraft:weathered_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] - minecraft:weathered_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] - minecraft:weathered_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] - minecraft:weathered_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] - minecraft:weathered_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] - minecraft:weathered_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] - minecraft:weathered_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] - minecraft:weathered_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] - minecraft:weathered_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] - minecraft:weathered_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] - minecraft:weathered_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] - minecraft:oxidized_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] - minecraft:oxidized_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] - minecraft:oxidized_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] - minecraft:oxidized_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] - minecraft:oxidized_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] - minecraft:oxidized_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] - minecraft:oxidized_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] - minecraft:oxidized_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] - minecraft:oxidized_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] - minecraft:oxidized_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] - minecraft:oxidized_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] - minecraft:oxidized_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] - minecraft:oxidized_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] - minecraft:oxidized_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] - minecraft:oxidized_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] - minecraft:oxidized_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] - minecraft:oxidized_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] - minecraft:oxidized_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] - minecraft:oxidized_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] - minecraft:oxidized_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] - minecraft:oxidized_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] - minecraft:oxidized_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] - minecraft:oxidized_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] - minecraft:oxidized_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] - minecraft:oxidized_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] - minecraft:oxidized_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] - minecraft:oxidized_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] - minecraft:oxidized_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] - minecraft:oxidized_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] - minecraft:oxidized_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] - minecraft:oxidized_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] - minecraft:oxidized_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] - minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] - minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] - -$$>=1.21.4#door: - minecraft:pale_oak_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=east,half=lower,hinge=left,open=false,powered=false] - minecraft:pale_oak_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] - minecraft:pale_oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] - minecraft:pale_oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] - minecraft:pale_oak_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=east,half=lower,hinge=left,open=true,powered=false] - minecraft:pale_oak_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=east,half=lower,hinge=right,open=true,powered=false] - minecraft:pale_oak_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=east,half=upper,hinge=left,open=true,powered=false] - minecraft:pale_oak_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=east,half=upper,hinge=right,open=true,powered=false] - minecraft:pale_oak_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=north,half=lower,hinge=left,open=false,powered=false] - minecraft:pale_oak_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=north,half=lower,hinge=right,open=false,powered=false] - minecraft:pale_oak_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=north,half=upper,hinge=left,open=false,powered=false] - minecraft:pale_oak_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=north,half=upper,hinge=right,open=false,powered=false] - minecraft:pale_oak_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=north,half=lower,hinge=left,open=true,powered=false] - minecraft:pale_oak_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=north,half=lower,hinge=right,open=true,powered=false] - minecraft:pale_oak_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=north,half=upper,hinge=left,open=true,powered=false] - minecraft:pale_oak_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=north,half=upper,hinge=right,open=true,powered=false] - minecraft:pale_oak_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=south,half=lower,hinge=left,open=false,powered=false] - minecraft:pale_oak_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] - minecraft:pale_oak_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=south,half=upper,hinge=left,open=false,powered=false] - minecraft:pale_oak_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=south,half=upper,hinge=right,open=false,powered=false] - minecraft:pale_oak_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=south,half=lower,hinge=left,open=true,powered=false] - minecraft:pale_oak_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=south,half=lower,hinge=right,open=true,powered=false] - minecraft:pale_oak_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=south,half=upper,hinge=left,open=true,powered=false] - minecraft:pale_oak_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=south,half=upper,hinge=right,open=true,powered=false] - minecraft:pale_oak_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=west,half=lower,hinge=left,open=false,powered=false] - minecraft:pale_oak_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] - minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=false,powered=false] - minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=false,powered=false] - minecraft:pale_oak_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=lower,hinge=left,open=true,powered=false] - minecraft:pale_oak_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=lower,hinge=right,open=true,powered=false] - minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=true,powered=false] - minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=true,powered=false] - -#### Fence Gate #### -minecraft:oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:oak_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:oak_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:oak_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:oak_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:oak_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:oak_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:oak_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:oak_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:spruce_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:spruce_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:spruce_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:spruce_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:spruce_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:spruce_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:spruce_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:spruce_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:spruce_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:spruce_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:spruce_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:spruce_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:spruce_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:spruce_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:spruce_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:spruce_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:spruce_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:spruce_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:spruce_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:spruce_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:spruce_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:spruce_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:spruce_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:spruce_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:spruce_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:spruce_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:spruce_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:spruce_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:spruce_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:spruce_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:birch_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:birch_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:birch_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:birch_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:birch_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:birch_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:birch_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:birch_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:birch_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:birch_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:birch_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:birch_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:birch_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:birch_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:birch_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:birch_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:birch_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:birch_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:birch_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:birch_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:birch_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:birch_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:birch_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:birch_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:birch_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:birch_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:birch_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:birch_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:birch_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:birch_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:jungle_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:jungle_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:jungle_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:jungle_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:jungle_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:jungle_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:jungle_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:jungle_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:jungle_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:jungle_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:jungle_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:jungle_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:jungle_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:jungle_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:jungle_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:jungle_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:jungle_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:jungle_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:jungle_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:jungle_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:jungle_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:jungle_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:jungle_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:jungle_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:jungle_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:jungle_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:jungle_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:jungle_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:jungle_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:jungle_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:acacia_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:acacia_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:acacia_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:acacia_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:acacia_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:acacia_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:acacia_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:acacia_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:acacia_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:acacia_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:acacia_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:acacia_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:acacia_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:acacia_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:acacia_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:acacia_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:acacia_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:acacia_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:acacia_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:acacia_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:acacia_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:acacia_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:acacia_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:acacia_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:acacia_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:acacia_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:acacia_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:acacia_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:acacia_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:acacia_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:dark_oak_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:dark_oak_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:dark_oak_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:dark_oak_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:dark_oak_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:dark_oak_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:dark_oak_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:dark_oak_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:mangrove_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:mangrove_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:mangrove_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:mangrove_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:mangrove_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:mangrove_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:mangrove_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:mangrove_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:mangrove_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:mangrove_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:mangrove_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:mangrove_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:mangrove_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:mangrove_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:mangrove_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:mangrove_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:cherry_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:cherry_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:cherry_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:cherry_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:cherry_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:cherry_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:cherry_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:cherry_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:cherry_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:cherry_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:cherry_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:cherry_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:cherry_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:cherry_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:cherry_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:cherry_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:cherry_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:cherry_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:cherry_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:cherry_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:cherry_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:cherry_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:cherry_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:cherry_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:cherry_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:cherry_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:cherry_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:cherry_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:cherry_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:cherry_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:cherry_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:cherry_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:bamboo_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:bamboo_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:bamboo_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:bamboo_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:bamboo_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:bamboo_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:bamboo_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:bamboo_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:bamboo_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:bamboo_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:bamboo_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:bamboo_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:bamboo_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:bamboo_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:bamboo_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:bamboo_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:crimson_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:crimson_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:crimson_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:crimson_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:crimson_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:crimson_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:crimson_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:crimson_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:crimson_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:crimson_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:crimson_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:crimson_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:crimson_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:crimson_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:crimson_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:crimson_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:crimson_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:crimson_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:crimson_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:crimson_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:crimson_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:crimson_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:crimson_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:crimson_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:crimson_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:crimson_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:crimson_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:crimson_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:crimson_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:crimson_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:crimson_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:crimson_fence_gate[facing=north,in_wall=true,open=true,powered=false] -minecraft:warped_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:warped_fence_gate[facing=east,in_wall=false,open=false,powered=false] -minecraft:warped_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:warped_fence_gate[facing=east,in_wall=false,open=true,powered=false] -minecraft:warped_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:warped_fence_gate[facing=east,in_wall=true,open=false,powered=false] -minecraft:warped_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:warped_fence_gate[facing=east,in_wall=true,open=true,powered=false] -minecraft:warped_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:warped_fence_gate[facing=south,in_wall=false,open=false,powered=false] -minecraft:warped_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:warped_fence_gate[facing=south,in_wall=false,open=true,powered=false] -minecraft:warped_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:warped_fence_gate[facing=south,in_wall=true,open=false,powered=false] -minecraft:warped_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:warped_fence_gate[facing=south,in_wall=true,open=true,powered=false] -minecraft:warped_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:warped_fence_gate[facing=west,in_wall=false,open=false,powered=false] -minecraft:warped_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:warped_fence_gate[facing=west,in_wall=false,open=true,powered=false] -minecraft:warped_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:warped_fence_gate[facing=west,in_wall=true,open=false,powered=false] -minecraft:warped_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:warped_fence_gate[facing=west,in_wall=true,open=true,powered=false] -minecraft:warped_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:warped_fence_gate[facing=north,in_wall=false,open=false,powered=false] -minecraft:warped_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:warped_fence_gate[facing=north,in_wall=false,open=true,powered=false] -minecraft:warped_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:warped_fence_gate[facing=north,in_wall=true,open=false,powered=false] -minecraft:warped_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:warped_fence_gate[facing=north,in_wall=true,open=true,powered=false] - -$$>=1.21.4#fence_gate: - minecraft:pale_oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=east,in_wall=false,open=false,powered=false] - minecraft:pale_oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=east,in_wall=false,open=true,powered=false] - minecraft:pale_oak_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=east,in_wall=true,open=false,powered=false] - minecraft:pale_oak_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=east,in_wall=true,open=true,powered=false] - minecraft:pale_oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=south,in_wall=false,open=false,powered=false] - minecraft:pale_oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=south,in_wall=false,open=true,powered=false] - minecraft:pale_oak_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=south,in_wall=true,open=false,powered=false] - minecraft:pale_oak_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=south,in_wall=true,open=true,powered=false] - minecraft:pale_oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=west,in_wall=false,open=false,powered=false] - minecraft:pale_oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=west,in_wall=false,open=true,powered=false] - minecraft:pale_oak_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=west,in_wall=true,open=false,powered=false] - minecraft:pale_oak_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=west,in_wall=true,open=true,powered=false] - minecraft:pale_oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false] - minecraft:pale_oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=north,in_wall=false,open=true,powered=false] - minecraft:pale_oak_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=north,in_wall=true,open=false,powered=false] - minecraft:pale_oak_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=north,in_wall=true,open=true,powered=false] - -#### Slab #### -minecraft:petrified_oak_slab[type=bottom,waterlogged=false]: minecraft:oak_slab[type=bottom,waterlogged=false] -minecraft:petrified_oak_slab[type=top,waterlogged=false]: minecraft:oak_slab[type=top,waterlogged=false] -minecraft:petrified_oak_slab[type=double,waterlogged=false]: minecraft:oak_slab[type=double,waterlogged=false] -minecraft:petrified_oak_slab[type=bottom,waterlogged=true]: minecraft:oak_slab[type=bottom,waterlogged=true] -minecraft:petrified_oak_slab[type=top,waterlogged=true]: minecraft:oak_slab[type=top,waterlogged=true] -minecraft:petrified_oak_slab[type=double,waterlogged=true]: minecraft:oak_slab[type=double,waterlogged=true] -minecraft:cut_copper_slab[type=bottom,waterlogged=false]: minecraft:waxed_cut_copper_slab[type=bottom,waterlogged=false] -minecraft:cut_copper_slab[type=top,waterlogged=false]: minecraft:waxed_cut_copper_slab[type=top,waterlogged=false] -minecraft:cut_copper_slab[type=double,waterlogged=false]: minecraft:waxed_cut_copper_slab[type=double,waterlogged=false] -minecraft:cut_copper_slab[type=bottom,waterlogged=true]: minecraft:waxed_cut_copper_slab[type=bottom,waterlogged=true] -minecraft:cut_copper_slab[type=top,waterlogged=true]: minecraft:waxed_cut_copper_slab[type=top,waterlogged=true] -minecraft:cut_copper_slab[type=double,waterlogged=true]: minecraft:waxed_cut_copper_slab[type=double,waterlogged=true] -minecraft:exposed_cut_copper_slab[type=bottom,waterlogged=false]: minecraft:waxed_exposed_cut_copper_slab[type=bottom,waterlogged=false] -minecraft:exposed_cut_copper_slab[type=top,waterlogged=false]: minecraft:waxed_exposed_cut_copper_slab[type=top,waterlogged=false] -minecraft:exposed_cut_copper_slab[type=double,waterlogged=false]: minecraft:waxed_exposed_cut_copper_slab[type=double,waterlogged=false] -minecraft:exposed_cut_copper_slab[type=bottom,waterlogged=true]: minecraft:waxed_exposed_cut_copper_slab[type=bottom,waterlogged=true] -minecraft:exposed_cut_copper_slab[type=top,waterlogged=true]: minecraft:waxed_exposed_cut_copper_slab[type=top,waterlogged=true] -minecraft:exposed_cut_copper_slab[type=double,waterlogged=true]: minecraft:waxed_exposed_cut_copper_slab[type=double,waterlogged=true] -minecraft:weathered_cut_copper_slab[type=bottom,waterlogged=false]: minecraft:waxed_weathered_cut_copper_slab[type=bottom,waterlogged=false] -minecraft:weathered_cut_copper_slab[type=top,waterlogged=false]: minecraft:waxed_weathered_cut_copper_slab[type=top,waterlogged=false] -minecraft:weathered_cut_copper_slab[type=double,waterlogged=false]: minecraft:waxed_weathered_cut_copper_slab[type=double,waterlogged=false] -minecraft:weathered_cut_copper_slab[type=bottom,waterlogged=true]: minecraft:waxed_weathered_cut_copper_slab[type=bottom,waterlogged=true] -minecraft:weathered_cut_copper_slab[type=top,waterlogged=true]: minecraft:waxed_weathered_cut_copper_slab[type=top,waterlogged=true] -minecraft:weathered_cut_copper_slab[type=double,waterlogged=true]: minecraft:waxed_weathered_cut_copper_slab[type=double,waterlogged=true] -minecraft:oxidized_cut_copper_slab[type=bottom,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_slab[type=bottom,waterlogged=false] -minecraft:oxidized_cut_copper_slab[type=top,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_slab[type=top,waterlogged=false] -minecraft:oxidized_cut_copper_slab[type=double,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_slab[type=double,waterlogged=false] -minecraft:oxidized_cut_copper_slab[type=bottom,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_slab[type=bottom,waterlogged=true] -minecraft:oxidized_cut_copper_slab[type=top,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_slab[type=top,waterlogged=true] -minecraft:oxidized_cut_copper_slab[type=double,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_slab[type=double,waterlogged=true] - -#### Stairs #### -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true] -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true] -minecraft:cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true] -minecraft:cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false] -minecraft:cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false] -minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false] -minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false] -minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true] - -#### Grate #### -# Suitable for making glass because it is completely transparent -$$>=1.20.3#grate: - minecraft:copper_grate[waterlogged=false]: minecraft:waxed_copper_grate[waterlogged=false] - minecraft:copper_grate[waterlogged=true]: minecraft:waxed_copper_grate[waterlogged=true] - minecraft:weathered_copper_grate[waterlogged=false]: minecraft:waxed_weathered_copper_grate[waterlogged=false] - minecraft:weathered_copper_grate[waterlogged=true]: minecraft:waxed_weathered_copper_grate[waterlogged=true] - minecraft:exposed_copper_grate[waterlogged=false]: minecraft:waxed_exposed_copper_grate[waterlogged=false] - minecraft:exposed_copper_grate[waterlogged=true]: minecraft:waxed_exposed_copper_grate[waterlogged=true] - minecraft:oxidized_copper_grate[waterlogged=false]: minecraft:waxed_oxidized_copper_grate[waterlogged=false] - minecraft:oxidized_copper_grate[waterlogged=true]: minecraft:waxed_oxidized_copper_grate[waterlogged=true] - -#### Pressure Plate #### -# Triggered pressure plates appear identical, even though they output different signal strengths. -minecraft:light_weighted_pressure_plate[power=2]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=3]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=4]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=5]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=6]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=7]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=8]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=9]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=10]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=11]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=12]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=13]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=14]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:light_weighted_pressure_plate[power=15]: minecraft:light_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=2]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=3]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=4]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=5]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=6]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=7]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=8]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=9]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=10]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=11]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=12]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=13]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=14]: minecraft:heavy_weighted_pressure_plate[power=1] -minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pressure_plate[power=1] - -#### Corals #### -# Coral blocks are ideal for creating water blocks or wall-mounted blocks. But you have to sacrifice its dry appearance. -# minecraft:dead_brain_coral[waterlogged=false]: minecraft:brain_coral[waterlogged=false] -# minecraft:dead_brain_coral[waterlogged=true]: minecraft:brain_coral[waterlogged=true] -# minecraft:dead_brain_coral_fan[waterlogged=false]: minecraft:brain_coral_fan[waterlogged=false] -# minecraft:dead_brain_coral_fan[waterlogged=true]: minecraft:brain_coral_fan[waterlogged=true] -# minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=east]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=east] -# minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=north]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=north] -# minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=south]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=south] -# minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=west]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=west] -# minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=east]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=east] -# minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=north]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=north] -# minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=south]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=south] -# minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=west]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=west] -# minecraft:dead_bubble_coral[waterlogged=false]: minecraft:bubble_coral[waterlogged=false] -# minecraft:dead_bubble_coral[waterlogged=true]: minecraft:bubble_coral[waterlogged=true] -# minecraft:dead_bubble_coral_fan[waterlogged=false]: minecraft:bubble_coral_fan[waterlogged=false] -# minecraft:dead_bubble_coral_fan[waterlogged=true]: minecraft:bubble_coral_fan[waterlogged=true] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=east] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=north] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=south] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=west] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=east] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=north] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=south] -# minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=west] -# minecraft:dead_fire_coral[waterlogged=false]: minecraft:fire_coral[waterlogged=false] -# minecraft:dead_fire_coral[waterlogged=true]: minecraft:fire_coral[waterlogged=true] -# minecraft:dead_fire_coral_fan[waterlogged=false]: minecraft:fire_coral_fan[waterlogged=false] -# minecraft:dead_fire_coral_fan[waterlogged=true]: minecraft:fire_coral_fan[waterlogged=true] -# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=east] -# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=north] -# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=south] -# minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=west] -# minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=east] -# minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=north] -# minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=south] -# minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=west] -# minecraft:dead_horn_coral[waterlogged=false]: minecraft:horn_coral[waterlogged=false] -# minecraft:dead_horn_coral[waterlogged=true]: minecraft:horn_coral[waterlogged=true] -# minecraft:dead_horn_coral_fan[waterlogged=false]: minecraft:horn_coral_fan[waterlogged=false] -# minecraft:dead_horn_coral_fan[waterlogged=true]: minecraft:horn_coral_fan[waterlogged=true] -# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=east] -# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=north] -# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=south] -# minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=west] -# minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=east] -# minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=north] -# minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=south] -# minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=west] -# minecraft:dead_tube_coral[waterlogged=false]: minecraft:tube_coral[waterlogged=false] -# minecraft:dead_tube_coral[waterlogged=true]: minecraft:tube_coral[waterlogged=true] -# minecraft:dead_tube_coral_fan[waterlogged=false]: minecraft:tube_coral_fan[waterlogged=false] -# minecraft:dead_tube_coral_fan[waterlogged=true]: minecraft:tube_coral_fan[waterlogged=true] -# minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=east]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=east] -# minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=north]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=north] -# minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=south]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=south] -# minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=west]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=west] -# minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=east]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=east] -# minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=north]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=north] -# minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=south]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=south] -# minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=west]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=west] - -#### Chorus Plant #### -# Chorus Plant does support transparent textures, but man... its hitbox is super weird. You're probably better off using leaves. -# minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] -# minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/amethyst_torch.yml b/common-files/src/main/resources/resources/default/configuration/blocks/amethyst_torch.yml index 84b5e29e0..773ea9c4e 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/amethyst_torch.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/amethyst_torch.yml @@ -1,7 +1,6 @@ items: default:amethyst_torch: material: nether_brick - custom-model-data: 3020 data: item-name: model: @@ -20,7 +19,6 @@ items: block: default:amethyst_wall_torch default:amethyst_standing_torch: material: nether_brick - custom-model-data: 3021 data: item-name: model: @@ -32,7 +30,6 @@ items: torch: minecraft:block/custom/amethyst_torch default:amethyst_wall_torch: material: nether_brick - custom-model-data: 3022 data: item-name: model: @@ -59,7 +56,6 @@ blocks: luminance: 15 item: default:amethyst_torch state: - id: 0 state: redstone_torch[lit=false] entity-renderer: item: default:amethyst_standing_torch @@ -146,16 +142,12 @@ blocks: variants: facing=north: appearance: north - id: 0 facing=east: appearance: east - id: 1 facing=west: appearance: west - id: 2 facing=south: appearance: south - id: 3 recipes: default:amethyst_torch: type: shaped diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml index 2ba57608c..07e6a3f1e 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml @@ -1,7 +1,6 @@ items: default:chessboard_block: material: nether_brick - custom-model-data: 3000 data: item-name: model: @@ -60,16 +59,12 @@ items: variants: facing=east: appearance: east - id: 18 facing=north: appearance: north - id: 19 facing=south: appearance: south - id: 20 facing=west: appearance: west - id: 21 recipes: default:chessboard_block: type: shaped diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml b/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml index 9a22722b8..4776b2d4d 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml @@ -1,7 +1,6 @@ items: default:chinese_lantern: material: nether_brick - custom-model-data: 3001 data: item-name: model: @@ -26,7 +25,6 @@ items: luminance: 15 map-color: 36 state: - id: 15 state: note_block:15 model: path: minecraft:block/custom/chinese_lantern diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml b/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml index 7edbe4e33..94185e5aa 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml @@ -1,7 +1,6 @@ items: default:copper_coil: material: nether_brick - custom-model-data: 3002 data: item-name: model: @@ -61,10 +60,8 @@ items: variants: lit=false: appearance: 'off' - id: 0 lit=true: appearance: 'on' - id: 1 settings: luminance: 8 recipes: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml b/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml index 6ccd4a673..ccb1fad33 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml @@ -1,7 +1,6 @@ items: default:ender_pearl_flower_seeds: material: nether_brick - custom-model-data: 3003 data: item-name: model: @@ -117,13 +116,10 @@ blocks: variants: age=0: appearance: stage_0 - id: 0 age=1: appearance: stage_1 - id: 1 age=2: appearance: stage_2 - id: 8 vanilla-loots: default:ender_pearl_flower_seeds_from_endermite: type: entity diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml b/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml index 4777b653c..5e2b00ba4 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml @@ -1,7 +1,6 @@ items: default:fairy_flower: material: nether_brick - custom-model-data: 3004 data: item-name: model: @@ -27,7 +26,6 @@ items: loot: template: default:loot_table/self state: - id: 0 state: sugar_cane:0 models: - path: minecraft:block/custom/fairy_flower_1 diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml b/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml index 6a43fc1cf..f24859eef 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml @@ -1,7 +1,6 @@ items: default:flame_cane: material: nether_brick - custom-model-data: 3005 data: item-name: model: @@ -71,22 +70,16 @@ items: variants: age=0: appearance: default - id: 2 age=1: appearance: default - id: 3 age=2: appearance: default - id: 4 age=3: appearance: default - id: 5 age=4: appearance: default - id: 6 age=5: appearance: default - id: 7 recipes: default:magma_cream: type: shaped diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml index 1bab9bb39..17ccff09d 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml @@ -1,7 +1,6 @@ items: default:gunpowder_block: material: nether_brick - custom-model-data: 3006 data: item-name: model: @@ -28,7 +27,6 @@ items: instrument: snare map-color: 45 state: - id: 16 state: note_block:16 model: path: minecraft:block/custom/gunpowder_block @@ -38,7 +36,6 @@ items: all: minecraft:block/custom/gunpowder_block default:solid_gunpowder_block: material: nether_brick - custom-model-data: 3007 data: item-name: model: @@ -62,7 +59,6 @@ items: instrument: basedrum map-color: 45 state: - id: 17 state: note_block:17 model: path: minecraft:block/custom/solid_gunpowder_block diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml index f9407d1f2..46e1b51e7 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml @@ -1,7 +1,6 @@ items: default:hami_melon_slice: material: melon_slice - custom-model-data: 1000 data: item-name: $$>=1.20.5: @@ -20,7 +19,6 @@ items: path: minecraft:item/custom/hami_melon_slice default:hami_melon: material: nether_brick - custom-model-data: 3023 data: item-name: model: @@ -32,7 +30,6 @@ items: block: default:hami_melon default:hami_melon_seeds: material: nether_brick - custom-model-data: 3024 data: item-name: model: @@ -82,7 +79,6 @@ blocks: - minecraft:mineable/axe - minecraft:sword_efficient state: - id: 30 state: note_block:30 model: template: default:model/cube @@ -144,28 +140,20 @@ blocks: variants: age=0: appearance: age=0 - id: 0 age=1: appearance: age=1 - id: 1 age=2: appearance: age=2 - id: 2 age=3: appearance: age=3 - id: 3 age=4: appearance: age=4 - id: 4 age=5: appearance: age=5 - id: 5 age=6: appearance: age=6 - id: 6 age=7: appearance: age=7 - id: 7 default:attached_hami_melon_stem: settings: template: @@ -205,16 +193,12 @@ blocks: variants: facing=east: appearance: facing=east - id: 0 facing=south: appearance: facing=south - id: 1 facing=west: appearance: facing=west - id: 2 facing=north: appearance: facing=north - id: 3 recipes: default:hami_melon: type: shaped diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/netherite_anvil.yml b/common-files/src/main/resources/resources/default/configuration/blocks/netherite_anvil.yml index add02ff3b..467ff359b 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/netherite_anvil.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/netherite_anvil.yml @@ -1,7 +1,6 @@ items: default:netherite_anvil: material: nether_brick - custom-model-data: 3008 data: item-name: model: @@ -18,6 +17,9 @@ items: type: falling_block hurt-amount: 4 max-hurt: 80 + sounds: + land: minecraft:block.anvil.land + destroy: minecraft:block.anvil.destroy events: - on: right_click functions: @@ -39,8 +41,6 @@ items: place: minecraft:block.anvil.place hit: minecraft:block.anvil.hit fall: minecraft:block.anvil.fall - land: minecraft:block.anvil.land - destroy: minecraft:block.anvil.destroy map-color: 29 hardness: 10.0 resistance: 1200 @@ -69,16 +69,12 @@ items: variants: facing_clockwise=east: appearance: axisX - id: 0 facing_clockwise=west: appearance: axisX - id: 1 facing_clockwise=north: appearance: axisZ - id: 2 facing_clockwise=south: appearance: axisZ - id: 3 recipes: default:netherite_anvil: type: shaped diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 7e5fcef3a..65268063a 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -1,7 +1,6 @@ items: default:palm_log: material: nether_brick - custom-model-data: 1000 settings: fuel-time: 300 tags: @@ -33,17 +32,8 @@ items: texture_side_path: minecraft:block/custom/palm_log model_vertical_path: minecraft:block/custom/palm_log model_horizontal_path: minecraft:block/custom/palm_log_horizontal - vanilla_id: - type: self_increase_int - from: 0 - to: 2 - internal_id: - type: self_increase_int - from: 0 - to: 2 default:stripped_palm_log: material: nether_brick - custom-model-data: 1001 settings: fuel-time: 300 tags: @@ -72,17 +62,8 @@ items: texture_side_path: minecraft:block/custom/stripped_palm_log model_vertical_path: minecraft:block/custom/stripped_palm_log model_horizontal_path: minecraft:block/custom/stripped_palm_log_horizontal - vanilla_id: - type: self_increase_int - from: 3 - to: 5 - internal_id: - type: self_increase_int - from: 3 - to: 5 default:palm_wood: material: nether_brick - custom-model-data: 1002 settings: fuel-time: 300 tags: @@ -114,17 +95,8 @@ items: texture_side_path: minecraft:block/custom/palm_log model_vertical_path: minecraft:block/custom/palm_wood model_horizontal_path: minecraft:block/custom/palm_wood_horizontal - vanilla_id: - type: self_increase_int - from: 6 - to: 8 - internal_id: - type: self_increase_int - from: 6 - to: 8 default:stripped_palm_wood: material: nether_brick - custom-model-data: 1003 settings: fuel-time: 300 tags: @@ -153,17 +125,8 @@ items: texture_side_path: minecraft:block/custom/stripped_palm_log model_vertical_path: minecraft:block/custom/stripped_palm_wood model_horizontal_path: minecraft:block/custom/stripped_palm_wood_horizontal - vanilla_id: - type: self_increase_int - from: 9 - to: 11 - internal_id: - type: self_increase_int - from: 9 - to: 11 default:palm_planks: material: nether_brick - custom-model-data: 1004 settings: fuel-time: 300 tags: @@ -188,11 +151,9 @@ items: template: default:model/simplified_cube_all arguments: path: minecraft:block/custom/palm_planks - id: 12 state: note_block:12 default:palm_sapling: material: nether_brick - custom-model-data: 1005 settings: fuel-time: 100 data: @@ -236,13 +197,10 @@ items: variants: stage=0: appearance: default - id: 0 stage=1: appearance: default - id: 1 default:palm_leaves: material: oak_leaves - custom-model-data: 1000 data: item-name: components: @@ -277,13 +235,8 @@ items: waterlogged_state: oak_leaves[distance=1,persistent=false,waterlogged=true] model_path: minecraft:block/custom/palm_leaves texture_path: minecraft:block/custom/palm_leaves - internal_id: - type: self_increase_int - from: 0 - to: 27 default:palm_trapdoor: material: nether_brick - custom-model-data: 1006 data: item-name: settings: @@ -338,7 +291,6 @@ items: texture: minecraft:block/custom/palm_trapdoor default:palm_door: material: nether_brick - custom-model-data: 1007 data: item-name: settings: @@ -413,7 +365,6 @@ items: textures: *textures default:palm_fence_gate: material: nether_brick - custom-model-data: 1008 data: item-name: settings: @@ -470,7 +421,6 @@ items: textures: *textures default:palm_slab: material: nether_brick - custom-model-data: 1009 data: item-name: settings: @@ -517,7 +467,6 @@ items: model_double_path: minecraft:block/custom/palm_planks default:palm_stairs: material: nether_brick - custom-model-data: 1013 model: type: minecraft:model path: minecraft:item/custom/palm_stairs @@ -567,7 +516,6 @@ items: textures: *textures default:palm_pressure_plate: material: nether_brick - custom-model-data: 1014 model: type: minecraft:model path: minecraft:item/custom/palm_pressure_plate @@ -608,8 +556,6 @@ items: arguments: normal_state: light_weighted_pressure_plate:0 powered_state: light_weighted_pressure_plate:1 - normal_id: 0 - powered_id: 1 model_normal_path: minecraft:block/custom/palm_pressure_plate model_normal_generation: parent: minecraft:block/pressure_plate_up @@ -624,7 +570,6 @@ items: items#pfence: default:palm_fence: material: nether_brick - custom-model-data: 1018 data: item-name: model: @@ -639,7 +584,6 @@ items#pfence: block: default:palm_fence default:palm_fence_post: material: nether_brick - custom-model-data: 1019 model: type: minecraft:model path: minecraft:block/custom/palm_fence_post @@ -649,7 +593,6 @@ items#pfence: texture: minecraft:block/custom/palm_planks default:palm_fence_side: material: nether_brick - custom-model-data: 1020 model: type: minecraft:model path: minecraft:block/custom/palm_fence_side @@ -689,15 +632,10 @@ blocks#fence: base_block: oak_fence fence_post_item: default:palm_fence_post fence_side_item: default:palm_fence_side - internal_id: - type: self_increase_int - from: 0 - to: 31 items#button: default:palm_button: material: nether_brick - custom-model-data: 1015 model: type: minecraft:model path: minecraft:item/custom/palm_button @@ -714,7 +652,6 @@ items#button: block: default:palm_button default:palm_button_pressed: material: nether_brick - custom-model-data: 1016 model: type: minecraft:model path: minecraft:block/custom/palm_button_pressed @@ -724,7 +661,6 @@ items#button: texture: minecraft:block/custom/palm_planks default:palm_button_not_pressed: material: nether_brick - custom-model-data: 1017 model: type: minecraft:model path: minecraft:block/custom/palm_button_not_pressed @@ -763,10 +699,6 @@ blocks#button: base_block: birch_button pressed_item: default:palm_button_pressed not_pressed_item: default:palm_button_not_pressed - internal_id: - type: self_increase_int - from: 0 - to: 23 recipes: default:palm_planks: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml b/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml index 9d5b8a502..5a164c44e 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml @@ -1,7 +1,6 @@ items: default:pebble: material: nether_brick - custom-model-data: 3009 data: item-name: model: @@ -103,13 +102,10 @@ items: variants: pebble=1: appearance: 'one' - id: 2 pebble=2: appearance: 'two' - id: 3 pebble=3: appearance: 'three' - id: 4 recipes: default:pebble: type: shapeless diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml b/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml index f444576b6..c43425c81 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml @@ -1,7 +1,6 @@ items: default:reed: material: nether_brick - custom-model-data: 3010 data: item-name: model: @@ -26,7 +25,6 @@ items: loot: template: default:loot_table/self state: - id: 1 state: sugar_cane:1 model: path: minecraft:block/custom/reed diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml index a1349bcbd..710804ef9 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml @@ -1,7 +1,6 @@ items: default:safe_block: material: nether_brick - custom-model-data: 3011 data: item-name: model: @@ -101,28 +100,20 @@ items: variants: facing=east,open=false: appearance: east - id: 22 facing=east,open=true: appearance: east_open - id: 23 facing=north,open=false: appearance: north - id: 24 facing=north,open=true: appearance: north_open - id: 25 facing=south,open=false: appearance: south - id: 26 facing=south,open=true: appearance: south_open - id: 27 facing=west,open=false: appearance: west - id: 28 facing=west,open=true: appearance: west_open - id: 29 recipes: default:safe_block: type: shaped diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml b/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml index 131392513..73ffa6029 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/sofa.yml @@ -1,7 +1,6 @@ items: default:sleeper_sofa: material: nether_brick - custom-model-data: 3012 data: item-name: model: @@ -37,19 +36,16 @@ items: bounce-height: 0.66 sync-player-position: false state: - id: 0 state: white_bed[facing=west,occupied=false,part=foot] entity-renderer: item: default:sleeper_sofa default:sofa_inner: material: nether_brick - custom-model-data: 3013 model: type: minecraft:model path: minecraft:item/custom/sofa_inner default:sofa: material: nether_brick - custom-model-data: 3014 data: item-name: model: @@ -150,37 +146,25 @@ items: variants: facing=east,shape=inner_left: appearance: facing=east,shape=inner_left - id: 0 facing=east,shape=inner_right: appearance: facing=east,shape=inner_right - id: 1 facing=east,shape=straight: appearance: facing=east,shape=straight - id: 2 facing=north,shape=inner_left: appearance: facing=north,shape=inner_left - id: 3 facing=north,shape=inner_right: appearance: facing=north,shape=inner_right - id: 4 facing=north,shape=straight: appearance: facing=north,shape=straight - id: 5 facing=south,shape=inner_left: appearance: facing=south,shape=inner_left - id: 6 facing=south,shape=inner_right: appearance: facing=south,shape=inner_right - id: 7 facing=south,shape=straight: appearance: facing=south,shape=straight - id: 8 facing=west,shape=inner_left: appearance: facing=west,shape=inner_left - id: 9 facing=west,shape=inner_right: appearance: facing=west,shape=inner_right - id: 10 facing=west,shape=straight: - appearance: facing=west,shape=straight - id: 11 \ No newline at end of file + appearance: facing=west,shape=straight \ No newline at end of file diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml b/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml index 7539c0882..7f7165c56 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/table_lamp.yml @@ -1,7 +1,6 @@ items: default:table_lamp: material: nether_brick - custom-model-data: 3015 data: item-name: model: @@ -80,39 +79,30 @@ items: variants: facing=east,lit=false: appearance: east_off - id: 12 facing=north,lit=false: appearance: north_off - id: 13 facing=south,lit=false: appearance: south_off - id: 14 facing=west,lit=false: appearance: west_off - id: 15 facing=east,lit=true: appearance: east_on - id: 16 settings: luminance: 15 facing=north,lit=true: appearance: north_on - id: 17 settings: luminance: 15 facing=south,lit=true: appearance: south_on - id: 18 settings: luminance: 15 facing=west,lit=true: appearance: west_on - id: 19 settings: luminance: 15 default:table_lamp_on: material: nether_brick - custom-model-data: 3016 model: type: minecraft:model path: minecraft:item/custom/table_lamp_on diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml b/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml index 067cc0a09..0eee914e4 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml @@ -1,7 +1,6 @@ items: default:topaz_ore: material: nether_brick - custom-model-data: 3017 data: item-name: model: @@ -14,7 +13,6 @@ items: block: default:topaz_ore default:deepslate_topaz_ore: material: nether_brick - custom-model-data: 3018 data: item-name: model: @@ -27,7 +25,6 @@ items: block: default:deepslate_topaz_ore default:topaz: material: nether_brick - custom-model-data: 3019 settings: anvil-repair-item: - target: @@ -53,7 +50,6 @@ blocks: arguments: break_power: 2 state: - id: 13 state: note_block:13 model: template: default:model/simplified_cube_all @@ -72,7 +68,6 @@ blocks: arguments: break_power: 2 state: - id: 14 state: note_block:14 model: template: default:model/simplified_cube_all diff --git a/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml b/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml index e5eb93aa2..16bab5968 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture/bench.yml @@ -1,7 +1,6 @@ items: default:bench: material: nether_brick - custom-model-data: 2000 data: item-name: model: diff --git a/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml b/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml index 2a008d707..fff66d0d4 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture/flower_basket.yml @@ -1,7 +1,6 @@ items: default:flower_basket: material: nether_brick - custom-model-data: 2001 data: item-name: model: @@ -13,19 +12,16 @@ items: furniture: default:flower_basket default:flower_basket_ground: material: nether_brick - custom-model-data: 2002 model: type: minecraft:model path: minecraft:item/custom/flower_basket_ground default:flower_basket_wall: material: nether_brick - custom-model-data: 2003 model: type: minecraft:model path: minecraft:item/custom/flower_basket_wall default:flower_basket_ceiling: material: nether_brick - custom-model-data: 2004 model: type: minecraft:model path: minecraft:item/custom/flower_basket_ceiling diff --git a/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml b/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml index f835379c3..ef848f6fc 100644 --- a/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml +++ b/common-files/src/main/resources/resources/default/configuration/furniture/wooden_chair.yml @@ -1,7 +1,6 @@ items: default:wooden_chair: material: nether_brick - custom-model-data: 2005 data: item-name: model: diff --git a/common-files/src/main/resources/resources/default/configuration/items/cap.yml b/common-files/src/main/resources/resources/default/configuration/items/cap.yml index ab797c99a..f682b7cc5 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/cap.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/cap.yml @@ -2,7 +2,6 @@ items: default:cap: material: leather_helmet client-bound-material: leather_horse_armor - custom-model-data: 1000 data: item-name: unbreakable: true diff --git a/common-files/src/main/resources/resources/default/configuration/items/flame_elytra.yml b/common-files/src/main/resources/resources/default/configuration/items/flame_elytra.yml index 6ec20e315..43425ae92 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/flame_elytra.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/flame_elytra.yml @@ -2,7 +2,6 @@ items: $$>=1.21.2#flame_elytra: default:flame_elytra: material: elytra - custom-model-data: 1000 settings: equippable: slot: chest diff --git a/common-files/src/main/resources/resources/default/configuration/items/gui_head.yml b/common-files/src/main/resources/resources/default/configuration/items/gui_head.yml index 9a6b67a8b..1c13ffa1e 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/gui_head.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/gui_head.yml @@ -1,8 +1,6 @@ items: default:gui_head_size_1: material: player_head - custom-model-data: 1000 - item-model: default:gui_head_size_1 model: type: minecraft:special path: minecraft:item/custom/gui_head_size_1 @@ -17,8 +15,6 @@ items: type: minecraft:player_head default:gui_head_size_4: material: player_head - custom-model-data: 1001 - item-model: default:gui_head_size_4 model: type: minecraft:special path: minecraft:item/custom/gui_head_size_4 diff --git a/common-files/src/main/resources/resources/default/configuration/items/topaz_armor.yml b/common-files/src/main/resources/resources/default/configuration/items/topaz_armor.yml index bde573c46..fcbaf8c86 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/topaz_armor.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/topaz_armor.yml @@ -1,7 +1,6 @@ templates: default:armor/topaz: material: chainmail_${part} - custom-model-data: 1000 data: item-name: <#FF8C00> tooltip-style: minecraft:topaz diff --git a/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml b/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml index 5102ab3f6..3e2114151 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml @@ -1,7 +1,6 @@ items: default:topaz_rod: material: fishing_rod - custom-model-data: 1000 settings: tags: - default:topaz_tools @@ -15,7 +14,6 @@ items: cast_path: minecraft:item/custom/topaz_rod_cast default:topaz_bow: material: bow - custom-model-data: 1000 settings: tags: - default:topaz_tools @@ -31,7 +29,6 @@ items: pulling_2_path: minecraft:item/custom/topaz_bow_pulling_2 default:topaz_crossbow: material: crossbow - custom-model-data: 1000 settings: tags: - default:topaz_tools @@ -49,7 +46,6 @@ items: firework_path: minecraft:item/custom/topaz_crossbow_firework default:topaz_pickaxe: material: golden_pickaxe - custom-model-data: 1000 settings: tags: - default:topaz_tools @@ -64,7 +60,6 @@ items: path: minecraft:item/custom/topaz_pickaxe default:topaz_axe: material: golden_axe - custom-model-data: 1000 settings: tags: - default:topaz_tools @@ -79,7 +74,6 @@ items: path: minecraft:item/custom/topaz_axe default:topaz_hoe: material: golden_hoe - custom-model-data: 1000 settings: tags: - default:topaz_tools @@ -94,7 +88,6 @@ items: path: minecraft:item/custom/topaz_hoe default:topaz_shovel: material: golden_shovel - custom-model-data: 1000 settings: tags: - default:topaz_tools @@ -109,7 +102,6 @@ items: path: minecraft:item/custom/topaz_shovel default:topaz_sword: material: golden_sword - custom-model-data: 1000 settings: tags: - default:topaz_tools @@ -125,7 +117,6 @@ items: $$>=1.21.4#topaz_trident: default:topaz_trident: material: trident - custom-model-data: 1000 settings: projectile: item: default:topaz_trident @@ -176,7 +167,6 @@ items: client-bound-material: $$1.20.1~1.21.1: bow $$1.21.2~1.21.3: honey_bottle - custom-model-data: 1001 data: item-name: <#FF8C00> components: 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 fa284b068..4403a7a15 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -862,7 +862,7 @@ templates#block_states: default: y appearances: axisY: - state: ${base_block}:${vanilla_id} + state: ${base_block} model: path: ${model_vertical_path} generation: @@ -871,7 +871,7 @@ templates#block_states: end: ${texture_top_path} side: ${texture_side_path} axisX: - state: ${base_block}:${vanilla_id} + state: ${base_block} model: x: 90 y: 90 @@ -882,7 +882,7 @@ templates#block_states: end: ${texture_top_path} side: ${texture_side_path} axisZ: - state: ${base_block}:${vanilla_id} + state: ${base_block} model: x: 90 path: ${model_horizontal_path} @@ -894,13 +894,10 @@ templates#block_states: variants: axis=x: appearance: axisX - id: ${internal_id} axis=y: appearance: axisY - id: ${internal_id} axis=z: appearance: axisZ - id: ${internal_id} # leaves block default:block_state/leaves: properties: @@ -930,93 +927,72 @@ templates#block_states: variants: distance=1,persistent=false,waterlogged=false: appearance: default - id: ${internal_id} distance=2,persistent=false,waterlogged=false: appearance: default - id: ${internal_id} distance=3,persistent=false,waterlogged=false: appearance: default - id: ${internal_id} distance=4,persistent=false,waterlogged=false: appearance: default - id: ${internal_id} distance=5,persistent=false,waterlogged=false: appearance: default - id: ${internal_id} distance=6,persistent=false,waterlogged=false: appearance: default - id: ${internal_id} distance=7,persistent=false,waterlogged=false: appearance: default - id: ${internal_id} settings: is-randomly-ticking: true distance=1,persistent=true,waterlogged=false: appearance: default - id: ${internal_id} distance=2,persistent=true,waterlogged=false: appearance: default - id: ${internal_id} distance=3,persistent=true,waterlogged=false: appearance: default - id: ${internal_id} distance=4,persistent=true,waterlogged=false: appearance: default - id: ${internal_id} distance=5,persistent=true,waterlogged=false: appearance: default - id: ${internal_id} distance=6,persistent=true,waterlogged=false: appearance: default - id: ${internal_id} distance=7,persistent=true,waterlogged=false: appearance: default - id: ${internal_id} distance=1,persistent=false,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=2,persistent=false,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=3,persistent=false,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=4,persistent=false,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=5,persistent=false,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=6,persistent=false,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=7,persistent=false,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false @@ -1024,49 +1000,42 @@ templates#block_states: fluid-state: water distance=1,persistent=true,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=2,persistent=true,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=3,persistent=true,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=4,persistent=true,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=5,persistent=true,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=6,persistent=true,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water distance=7,persistent=true,waterlogged=true: appearance: waterlogged - id: ${internal_id} settings: resistance: 1200.0 burnable: false @@ -1256,318 +1225,254 @@ templates#block_states: variants: facing=east,half=bottom,open=false,powered=false,waterlogged=false: appearance: facing=east,half=bottom,open=false,waterlogged=false - id: 0 facing=east,half=bottom,open=false,powered=true,waterlogged=false: appearance: facing=east,half=bottom,open=false,waterlogged=false - id: 1 facing=east,half=bottom,open=true,powered=false,waterlogged=false: appearance: facing=east,half=bottom,open=true,waterlogged=false - id: 2 facing=east,half=bottom,open=true,powered=true,waterlogged=false: appearance: facing=east,half=bottom,open=true,waterlogged=false - id: 3 facing=east,half=top,open=false,powered=false,waterlogged=false: appearance: facing=east,half=top,open=false,waterlogged=false - id: 4 facing=east,half=top,open=false,powered=true,waterlogged=false: appearance: facing=east,half=top,open=false,waterlogged=false - id: 5 facing=east,half=top,open=true,powered=false,waterlogged=false: appearance: facing=east,half=top,open=true,waterlogged=false - id: 6 facing=east,half=top,open=true,powered=true,waterlogged=false: appearance: facing=east,half=top,open=true,waterlogged=false - id: 7 facing=north,half=bottom,open=false,powered=false,waterlogged=false: appearance: facing=north,half=bottom,open=false,waterlogged=false - id: 8 facing=north,half=bottom,open=false,powered=true,waterlogged=false: appearance: facing=north,half=bottom,open=false,waterlogged=false - id: 9 facing=north,half=bottom,open=true,powered=false,waterlogged=false: appearance: facing=north,half=bottom,open=true,waterlogged=false - id: 10 facing=north,half=bottom,open=true,powered=true,waterlogged=false: appearance: facing=north,half=bottom,open=true,waterlogged=false - id: 11 facing=north,half=top,open=false,powered=false,waterlogged=false: appearance: facing=north,half=top,open=false,waterlogged=false - id: 12 facing=north,half=top,open=false,powered=true,waterlogged=false: appearance: facing=north,half=top,open=false,waterlogged=false - id: 13 facing=north,half=top,open=true,powered=false,waterlogged=false: appearance: facing=north,half=top,open=true,waterlogged=false - id: 14 facing=north,half=top,open=true,powered=true,waterlogged=false: appearance: facing=north,half=top,open=true,waterlogged=false - id: 15 facing=south,half=bottom,open=false,powered=false,waterlogged=false: appearance: facing=south,half=bottom,open=false,waterlogged=false - id: 16 facing=south,half=bottom,open=false,powered=true,waterlogged=false: appearance: facing=south,half=bottom,open=false,waterlogged=false - id: 17 facing=south,half=bottom,open=true,powered=false,waterlogged=false: appearance: facing=south,half=bottom,open=true,waterlogged=false - id: 18 facing=south,half=bottom,open=true,powered=true,waterlogged=false: appearance: facing=south,half=bottom,open=true,waterlogged=false - id: 19 facing=south,half=top,open=false,powered=false,waterlogged=false: appearance: facing=south,half=top,open=false,waterlogged=false - id: 20 facing=south,half=top,open=false,powered=true,waterlogged=false: appearance: facing=south,half=top,open=false,waterlogged=false - id: 21 facing=south,half=top,open=true,powered=false,waterlogged=false: appearance: facing=south,half=top,open=true,waterlogged=false - id: 22 facing=south,half=top,open=true,powered=true,waterlogged=false: appearance: facing=south,half=top,open=true,waterlogged=false - id: 23 facing=west,half=bottom,open=false,powered=false,waterlogged=false: appearance: facing=west,half=bottom,open=false,waterlogged=false - id: 24 facing=west,half=bottom,open=false,powered=true,waterlogged=false: appearance: facing=west,half=bottom,open=false,waterlogged=false - id: 25 facing=west,half=bottom,open=true,powered=false,waterlogged=false: appearance: facing=west,half=bottom,open=true,waterlogged=false - id: 26 facing=west,half=bottom,open=true,powered=true,waterlogged=false: appearance: facing=west,half=bottom,open=true,waterlogged=false - id: 27 facing=west,half=top,open=false,powered=false,waterlogged=false: appearance: facing=west,half=top,open=false,waterlogged=false - id: 28 facing=west,half=top,open=false,powered=true,waterlogged=false: appearance: facing=west,half=top,open=false,waterlogged=false - id: 29 facing=west,half=top,open=true,powered=false,waterlogged=false: appearance: facing=west,half=top,open=true,waterlogged=false - id: 30 facing=west,half=top,open=true,powered=true,waterlogged=false: appearance: facing=west,half=top,open=true,waterlogged=false - id: 31 facing=east,half=bottom,open=false,powered=false,waterlogged=true: appearance: facing=east,half=bottom,open=false,waterlogged=true - id: 32 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=bottom,open=false,powered=true,waterlogged=true: appearance: facing=east,half=bottom,open=false,waterlogged=true - id: 33 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=bottom,open=true,powered=false,waterlogged=true: appearance: facing=east,half=bottom,open=true,waterlogged=true - id: 34 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=bottom,open=true,powered=true,waterlogged=true: appearance: facing=east,half=bottom,open=true,waterlogged=true - id: 35 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=top,open=false,powered=false,waterlogged=true: appearance: facing=east,half=top,open=false,waterlogged=true - id: 36 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=top,open=false,powered=true,waterlogged=true: appearance: facing=east,half=top,open=false,waterlogged=true - id: 37 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=top,open=true,powered=false,waterlogged=true: appearance: facing=east,half=top,open=true,waterlogged=true - id: 38 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=top,open=true,powered=true,waterlogged=true: appearance: facing=east,half=top,open=true,waterlogged=true - id: 39 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=bottom,open=false,powered=false,waterlogged=true: appearance: facing=north,half=bottom,open=false,waterlogged=true - id: 40 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=bottom,open=false,powered=true,waterlogged=true: appearance: facing=north,half=bottom,open=false,waterlogged=true - id: 41 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=bottom,open=true,powered=false,waterlogged=true: appearance: facing=north,half=bottom,open=true,waterlogged=true - id: 42 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=bottom,open=true,powered=true,waterlogged=true: appearance: facing=north,half=bottom,open=true,waterlogged=true - id: 43 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=top,open=false,powered=false,waterlogged=true: appearance: facing=north,half=top,open=false,waterlogged=true - id: 44 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=top,open=false,powered=true,waterlogged=true: appearance: facing=north,half=top,open=false,waterlogged=true - id: 45 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=top,open=true,powered=false,waterlogged=true: appearance: facing=north,half=top,open=true,waterlogged=true - id: 46 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=top,open=true,powered=true,waterlogged=true: appearance: facing=north,half=top,open=true,waterlogged=true - id: 47 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=bottom,open=false,powered=false,waterlogged=true: appearance: facing=south,half=bottom,open=false,waterlogged=true - id: 48 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=bottom,open=false,powered=true,waterlogged=true: appearance: facing=south,half=bottom,open=false,waterlogged=true - id: 49 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=bottom,open=true,powered=false,waterlogged=true: appearance: facing=south,half=bottom,open=true,waterlogged=true - id: 50 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=bottom,open=true,powered=true,waterlogged=true: appearance: facing=south,half=bottom,open=true,waterlogged=true - id: 51 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=top,open=false,powered=false,waterlogged=true: appearance: facing=south,half=top,open=false,waterlogged=true - id: 52 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=top,open=false,powered=true,waterlogged=true: appearance: facing=south,half=top,open=false,waterlogged=true - id: 53 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=top,open=true,powered=false,waterlogged=true: appearance: facing=south,half=top,open=true,waterlogged=true - id: 54 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=top,open=true,powered=true,waterlogged=true: appearance: facing=south,half=top,open=true,waterlogged=true - id: 55 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=bottom,open=false,powered=false,waterlogged=true: appearance: facing=west,half=bottom,open=false,waterlogged=true - id: 56 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=bottom,open=false,powered=true,waterlogged=true: appearance: facing=west,half=bottom,open=false,waterlogged=true - id: 57 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=bottom,open=true,powered=false,waterlogged=true: appearance: facing=west,half=bottom,open=true,waterlogged=true - id: 58 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=bottom,open=true,powered=true,waterlogged=true: appearance: facing=west,half=bottom,open=true,waterlogged=true - id: 59 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=top,open=false,powered=false,waterlogged=true: appearance: facing=west,half=top,open=false,waterlogged=true - id: 60 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=top,open=false,powered=true,waterlogged=true: appearance: facing=west,half=top,open=false,waterlogged=true - id: 61 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=top,open=true,powered=false,waterlogged=true: appearance: facing=west,half=top,open=true,waterlogged=true - id: 62 settings: fluid-state: water facing=west,half=top,open=true,powered=true,waterlogged=true: appearance: facing=west,half=top,open=true,waterlogged=true - id: 63 settings: resistance: 1200.0 burnable: false @@ -1751,196 +1656,132 @@ templates#block_states: variants: facing=east,half=lower,hinge=left,open=false,powered=true: appearance: facing=east,half=lower,hinge=left,open=false - id: 0 facing=east,half=lower,hinge=left,open=false,powered=false: appearance: facing=east,half=lower,hinge=left,open=false - id: 1 facing=east,half=lower,hinge=right,open=false,powered=true: appearance: facing=east,half=lower,hinge=right,open=false - id: 2 facing=east,half=lower,hinge=right,open=false,powered=false: appearance: facing=east,half=lower,hinge=right,open=false - id: 3 facing=east,half=upper,hinge=left,open=false,powered=true: appearance: facing=east,half=upper,hinge=left,open=false - id: 4 facing=east,half=upper,hinge=left,open=false,powered=false: appearance: facing=east,half=upper,hinge=left,open=false - id: 5 facing=east,half=upper,hinge=right,open=false,powered=true: appearance: facing=east,half=upper,hinge=right,open=false - id: 6 facing=east,half=upper,hinge=right,open=false,powered=false: appearance: facing=east,half=upper,hinge=right,open=false - id: 7 facing=north,half=lower,hinge=left,open=false,powered=true: appearance: facing=north,half=lower,hinge=left,open=false - id: 8 facing=north,half=lower,hinge=left,open=false,powered=false: appearance: facing=north,half=lower,hinge=left,open=false - id: 9 facing=north,half=lower,hinge=right,open=false,powered=true: appearance: facing=north,half=lower,hinge=right,open=false - id: 10 facing=north,half=lower,hinge=right,open=false,powered=false: appearance: facing=north,half=lower,hinge=right,open=false - id: 11 facing=north,half=upper,hinge=left,open=false,powered=true: appearance: facing=north,half=upper,hinge=left,open=false - id: 12 facing=north,half=upper,hinge=left,open=false,powered=false: appearance: facing=north,half=upper,hinge=left,open=false - id: 13 facing=north,half=upper,hinge=right,open=false,powered=true: appearance: facing=north,half=upper,hinge=right,open=false - id: 14 facing=north,half=upper,hinge=right,open=false,powered=false: appearance: facing=north,half=upper,hinge=right,open=false - id: 15 facing=south,half=lower,hinge=left,open=false,powered=true: appearance: facing=south,half=lower,hinge=left,open=false - id: 16 facing=south,half=lower,hinge=left,open=false,powered=false: appearance: facing=south,half=lower,hinge=left,open=false - id: 17 facing=south,half=lower,hinge=right,open=false,powered=true: appearance: facing=south,half=lower,hinge=right,open=false - id: 18 facing=south,half=lower,hinge=right,open=false,powered=false: appearance: facing=south,half=lower,hinge=right,open=false - id: 19 facing=south,half=upper,hinge=left,open=false,powered=true: appearance: facing=south,half=upper,hinge=left,open=false - id: 20 facing=south,half=upper,hinge=left,open=false,powered=false: appearance: facing=south,half=upper,hinge=left,open=false - id: 21 facing=south,half=upper,hinge=right,open=false,powered=true: appearance: facing=south,half=upper,hinge=right,open=false - id: 22 facing=south,half=upper,hinge=right,open=false,powered=false: appearance: facing=south,half=upper,hinge=right,open=false - id: 23 facing=west,half=lower,hinge=left,open=false,powered=true: appearance: facing=west,half=lower,hinge=left,open=false - id: 24 facing=west,half=lower,hinge=left,open=false,powered=false: appearance: facing=west,half=lower,hinge=left,open=false - id: 25 facing=west,half=lower,hinge=right,open=false,powered=true: appearance: facing=west,half=lower,hinge=right,open=false - id: 26 facing=west,half=lower,hinge=right,open=false,powered=false: appearance: facing=west,half=lower,hinge=right,open=false - id: 27 facing=west,half=upper,hinge=left,open=false,powered=true: appearance: facing=west,half=upper,hinge=left,open=false - id: 28 facing=west,half=upper,hinge=left,open=false,powered=false: appearance: facing=west,half=upper,hinge=left,open=false - id: 29 facing=west,half=upper,hinge=right,open=false,powered=true: appearance: facing=west,half=upper,hinge=right,open=false - id: 30 facing=west,half=upper,hinge=right,open=false,powered=false: appearance: facing=west,half=upper,hinge=right,open=false - id: 31 facing=east,half=lower,hinge=left,open=true,powered=true: appearance: facing=east,half=lower,hinge=left,open=true - id: 32 facing=east,half=lower,hinge=left,open=true,powered=false: appearance: facing=east,half=lower,hinge=left,open=true - id: 33 facing=east,half=lower,hinge=right,open=true,powered=true: appearance: facing=east,half=lower,hinge=right,open=true - id: 34 facing=east,half=lower,hinge=right,open=true,powered=false: appearance: facing=east,half=lower,hinge=right,open=true - id: 35 facing=east,half=upper,hinge=left,open=true,powered=true: appearance: facing=east,half=upper,hinge=left,open=true - id: 36 facing=east,half=upper,hinge=left,open=true,powered=false: appearance: facing=east,half=upper,hinge=left,open=true - id: 37 facing=east,half=upper,hinge=right,open=true,powered=true: appearance: facing=east,half=upper,hinge=right,open=true - id: 38 facing=east,half=upper,hinge=right,open=true,powered=false: appearance: facing=east,half=upper,hinge=right,open=true - id: 39 facing=north,half=lower,hinge=left,open=true,powered=true: appearance: facing=north,half=lower,hinge=left,open=true - id: 40 facing=north,half=lower,hinge=left,open=true,powered=false: appearance: facing=north,half=lower,hinge=left,open=true - id: 41 facing=north,half=lower,hinge=right,open=true,powered=true: appearance: facing=north,half=lower,hinge=right,open=true - id: 42 facing=north,half=lower,hinge=right,open=true,powered=false: appearance: facing=north,half=lower,hinge=right,open=true - id: 43 facing=north,half=upper,hinge=left,open=true,powered=true: appearance: facing=north,half=upper,hinge=left,open=true - id: 44 facing=north,half=upper,hinge=left,open=true,powered=false: appearance: facing=north,half=upper,hinge=left,open=true - id: 45 facing=north,half=upper,hinge=right,open=true,powered=true: appearance: facing=north,half=upper,hinge=right,open=true - id: 46 facing=north,half=upper,hinge=right,open=true,powered=false: appearance: facing=north,half=upper,hinge=right,open=true - id: 47 facing=south,half=lower,hinge=left,open=true,powered=true: appearance: facing=south,half=lower,hinge=left,open=true - id: 48 facing=south,half=lower,hinge=left,open=true,powered=false: appearance: facing=south,half=lower,hinge=left,open=true - id: 49 facing=south,half=lower,hinge=right,open=true,powered=true: appearance: facing=south,half=lower,hinge=right,open=true - id: 50 facing=south,half=lower,hinge=right,open=true,powered=false: appearance: facing=south,half=lower,hinge=right,open=true - id: 51 facing=south,half=upper,hinge=left,open=true,powered=true: appearance: facing=south,half=upper,hinge=left,open=true - id: 52 facing=south,half=upper,hinge=left,open=true,powered=false: appearance: facing=south,half=upper,hinge=left,open=true - id: 53 facing=south,half=upper,hinge=right,open=true,powered=true: appearance: facing=south,half=upper,hinge=right,open=true - id: 54 facing=south,half=upper,hinge=right,open=true,powered=false: appearance: facing=south,half=upper,hinge=right,open=true - id: 55 facing=west,half=lower,hinge=left,open=true,powered=true: appearance: facing=west,half=lower,hinge=left,open=true - id: 56 facing=west,half=lower,hinge=left,open=true,powered=false: appearance: facing=west,half=lower,hinge=left,open=true - id: 57 facing=west,half=lower,hinge=right,open=true,powered=true: appearance: facing=west,half=lower,hinge=right,open=true - id: 58 facing=west,half=lower,hinge=right,open=true,powered=false: appearance: facing=west,half=lower,hinge=right,open=true - id: 59 facing=west,half=upper,hinge=left,open=true,powered=true: appearance: facing=west,half=upper,hinge=left,open=true - id: 60 facing=west,half=upper,hinge=left,open=true,powered=false: appearance: facing=west,half=upper,hinge=left,open=true - id: 61 facing=west,half=upper,hinge=right,open=true,powered=true: appearance: facing=west,half=upper,hinge=right,open=true - id: 62 facing=west,half=upper,hinge=right,open=true,powered=false: appearance: facing=west,half=upper,hinge=right,open=true - id: 63 # fence gate block default:block_state/fence_gate: properties: @@ -2055,100 +1896,68 @@ templates#block_states: variants: facing=east,in_wall=false,open=false,powered=true: appearance: facing=east,in_wall=false,open=false - id: 0 facing=east,in_wall=false,open=false,powered=false: appearance: facing=east,in_wall=false,open=false - id: 1 facing=east,in_wall=false,open=true,powered=true: appearance: facing=east,in_wall=false,open=true - id: 2 facing=east,in_wall=false,open=true,powered=false: appearance: facing=east,in_wall=false,open=true - id: 3 facing=east,in_wall=true,open=false,powered=true: appearance: facing=east,in_wall=true,open=false - id: 4 facing=east,in_wall=true,open=false,powered=false: appearance: facing=east,in_wall=true,open=false - id: 5 facing=east,in_wall=true,open=true,powered=true: appearance: facing=east,in_wall=true,open=true - id: 6 facing=east,in_wall=true,open=true,powered=false: appearance: facing=east,in_wall=true,open=true - id: 7 facing=south,in_wall=false,open=false,powered=true: appearance: facing=south,in_wall=false,open=false - id: 8 facing=south,in_wall=false,open=false,powered=false: appearance: facing=south,in_wall=false,open=false - id: 9 facing=south,in_wall=false,open=true,powered=true: appearance: facing=south,in_wall=false,open=true - id: 10 facing=south,in_wall=false,open=true,powered=false: appearance: facing=south,in_wall=false,open=true - id: 11 facing=south,in_wall=true,open=false,powered=true: appearance: facing=south,in_wall=true,open=false - id: 12 facing=south,in_wall=true,open=false,powered=false: appearance: facing=south,in_wall=true,open=false - id: 13 facing=south,in_wall=true,open=true,powered=true: appearance: facing=south,in_wall=true,open=true - id: 14 facing=south,in_wall=true,open=true,powered=false: appearance: facing=south,in_wall=true,open=true - id: 15 facing=west,in_wall=false,open=false,powered=true: appearance: facing=west,in_wall=false,open=false - id: 16 facing=west,in_wall=false,open=false,powered=false: appearance: facing=west,in_wall=false,open=false - id: 17 facing=west,in_wall=false,open=true,powered=true: appearance: facing=west,in_wall=false,open=true - id: 18 facing=west,in_wall=false,open=true,powered=false: appearance: facing=west,in_wall=false,open=true - id: 19 facing=west,in_wall=true,open=false,powered=true: appearance: facing=west,in_wall=true,open=false - id: 20 facing=west,in_wall=true,open=false,powered=false: appearance: facing=west,in_wall=true,open=false - id: 21 facing=west,in_wall=true,open=true,powered=true: appearance: facing=west,in_wall=true,open=true - id: 22 facing=west,in_wall=true,open=true,powered=false: appearance: facing=west,in_wall=true,open=true - id: 23 facing=north,in_wall=false,open=false,powered=true: appearance: facing=north,in_wall=false,open=false - id: 24 facing=north,in_wall=false,open=false,powered=false: appearance: facing=north,in_wall=false,open=false - id: 25 facing=north,in_wall=false,open=true,powered=true: appearance: facing=north,in_wall=false,open=true - id: 26 facing=north,in_wall=false,open=true,powered=false: appearance: facing=north,in_wall=false,open=true - id: 27 facing=north,in_wall=true,open=false,powered=true: appearance: facing=north,in_wall=true,open=false - id: 28 facing=north,in_wall=true,open=false,powered=false: appearance: facing=north,in_wall=true,open=false - id: 29 facing=north,in_wall=true,open=true,powered=true: appearance: facing=north,in_wall=true,open=true - id: 30 facing=north,in_wall=true,open=true,powered=false: appearance: facing=north,in_wall=true,open=true - id: 31 # slab block default:block_state/slab: properties: @@ -2189,30 +1998,24 @@ templates#block_states: variants: type=top,waterlogged=false: appearance: type=top,waterlogged=false - id: 0 type=bottom,waterlogged=false: appearance: type=bottom,waterlogged=false - id: 1 type=double,waterlogged=false: appearance: type=double,waterlogged=false - id: 2 type=top,waterlogged=true: appearance: type=top,waterlogged=true - id: 3 settings: resistance: 1200.0 burnable: false fluid-state: water type=bottom,waterlogged=true: appearance: type=bottom,waterlogged=true - id: 4 settings: resistance: 1200.0 burnable: false fluid-state: water type=double,waterlogged=true: appearance: type=double,waterlogged=true - id: 5 settings: resistance: 1200.0 burnable: false @@ -2726,400 +2529,320 @@ templates#block_states: variants: facing=east,half=bottom,shape=inner_left,waterlogged=false: appearance: facing=east,half=bottom,shape=inner_left,waterlogged=false - id: 0 facing=east,half=bottom,shape=inner_right,waterlogged=false: appearance: facing=east,half=bottom,shape=inner_right,waterlogged=false - id: 1 facing=east,half=bottom,shape=outer_left,waterlogged=false: appearance: facing=east,half=bottom,shape=outer_left,waterlogged=false - id: 2 facing=east,half=bottom,shape=outer_right,waterlogged=false: appearance: facing=east,half=bottom,shape=outer_right,waterlogged=false - id: 3 facing=east,half=bottom,shape=straight,waterlogged=false: appearance: facing=east,half=bottom,shape=straight,waterlogged=false - id: 4 facing=east,half=top,shape=inner_left,waterlogged=false: appearance: facing=east,half=top,shape=inner_left,waterlogged=false - id: 5 facing=east,half=top,shape=inner_right,waterlogged=false: appearance: facing=east,half=top,shape=inner_right,waterlogged=false - id: 6 facing=east,half=top,shape=outer_left,waterlogged=false: appearance: facing=east,half=top,shape=outer_left,waterlogged=false - id: 7 facing=east,half=top,shape=outer_right,waterlogged=false: appearance: facing=east,half=top,shape=outer_right,waterlogged=false - id: 8 facing=east,half=top,shape=straight,waterlogged=false: appearance: facing=east,half=top,shape=straight,waterlogged=false - id: 9 facing=north,half=bottom,shape=inner_left,waterlogged=false: appearance: facing=north,half=bottom,shape=inner_left,waterlogged=false - id: 10 facing=north,half=bottom,shape=inner_right,waterlogged=false: appearance: facing=north,half=bottom,shape=inner_right,waterlogged=false - id: 11 facing=north,half=bottom,shape=outer_left,waterlogged=false: appearance: facing=north,half=bottom,shape=outer_left,waterlogged=false - id: 12 facing=north,half=bottom,shape=outer_right,waterlogged=false: appearance: facing=north,half=bottom,shape=outer_right,waterlogged=false - id: 13 facing=north,half=bottom,shape=straight,waterlogged=false: appearance: facing=north,half=bottom,shape=straight,waterlogged=false - id: 14 facing=north,half=top,shape=inner_left,waterlogged=false: appearance: facing=north,half=top,shape=inner_left,waterlogged=false - id: 15 facing=north,half=top,shape=inner_right,waterlogged=false: appearance: facing=north,half=top,shape=inner_right,waterlogged=false - id: 16 facing=north,half=top,shape=outer_left,waterlogged=false: appearance: facing=north,half=top,shape=outer_left,waterlogged=false - id: 17 facing=north,half=top,shape=outer_right,waterlogged=false: appearance: facing=north,half=top,shape=outer_right,waterlogged=false - id: 18 facing=north,half=top,shape=straight,waterlogged=false: appearance: facing=north,half=top,shape=straight,waterlogged=false - id: 19 facing=south,half=bottom,shape=inner_left,waterlogged=false: appearance: facing=south,half=bottom,shape=inner_left,waterlogged=false - id: 20 facing=south,half=bottom,shape=inner_right,waterlogged=false: appearance: facing=south,half=bottom,shape=inner_right,waterlogged=false - id: 21 facing=south,half=bottom,shape=outer_left,waterlogged=false: appearance: facing=south,half=bottom,shape=outer_left,waterlogged=false - id: 22 facing=south,half=bottom,shape=outer_right,waterlogged=false: appearance: facing=south,half=bottom,shape=outer_right,waterlogged=false - id: 23 facing=south,half=bottom,shape=straight,waterlogged=false: appearance: facing=south,half=bottom,shape=straight,waterlogged=false - id: 24 facing=south,half=top,shape=inner_left,waterlogged=false: appearance: facing=south,half=top,shape=inner_left,waterlogged=false - id: 25 facing=south,half=top,shape=inner_right,waterlogged=false: appearance: facing=south,half=top,shape=inner_right,waterlogged=false - id: 26 facing=south,half=top,shape=outer_left,waterlogged=false: appearance: facing=south,half=top,shape=outer_left,waterlogged=false - id: 27 facing=south,half=top,shape=outer_right,waterlogged=false: appearance: facing=south,half=top,shape=outer_right,waterlogged=false - id: 28 facing=south,half=top,shape=straight,waterlogged=false: appearance: facing=south,half=top,shape=straight,waterlogged=false - id: 29 facing=west,half=bottom,shape=inner_left,waterlogged=false: appearance: facing=west,half=bottom,shape=inner_left,waterlogged=false - id: 30 facing=west,half=bottom,shape=inner_right,waterlogged=false: appearance: facing=west,half=bottom,shape=inner_right,waterlogged=false - id: 31 facing=west,half=bottom,shape=outer_left,waterlogged=false: appearance: facing=west,half=bottom,shape=outer_left,waterlogged=false - id: 32 facing=west,half=bottom,shape=outer_right,waterlogged=false: appearance: facing=west,half=bottom,shape=outer_right,waterlogged=false - id: 33 facing=west,half=bottom,shape=straight,waterlogged=false: appearance: facing=west,half=bottom,shape=straight,waterlogged=false - id: 34 facing=west,half=top,shape=inner_left,waterlogged=false: appearance: facing=west,half=top,shape=inner_left,waterlogged=false - id: 35 facing=west,half=top,shape=inner_right,waterlogged=false: appearance: facing=west,half=top,shape=inner_right,waterlogged=false - id: 36 facing=west,half=top,shape=outer_left,waterlogged=false: appearance: facing=west,half=top,shape=outer_left,waterlogged=false - id: 37 facing=west,half=top,shape=outer_right,waterlogged=false: appearance: facing=west,half=top,shape=outer_right,waterlogged=false - id: 38 facing=west,half=top,shape=straight,waterlogged=false: appearance: facing=west,half=top,shape=straight,waterlogged=false - id: 39 facing=east,half=bottom,shape=inner_left,waterlogged=true: appearance: facing=east,half=bottom,shape=inner_left,waterlogged=true - id: 40 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=bottom,shape=inner_right,waterlogged=true: appearance: facing=east,half=bottom,shape=inner_right,waterlogged=true - id: 41 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=bottom,shape=outer_left,waterlogged=true: appearance: facing=east,half=bottom,shape=outer_left,waterlogged=true - id: 42 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=bottom,shape=outer_right,waterlogged=true: appearance: facing=east,half=bottom,shape=outer_right,waterlogged=true - id: 43 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=bottom,shape=straight,waterlogged=true: appearance: facing=east,half=bottom,shape=straight,waterlogged=true - id: 44 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=top,shape=inner_left,waterlogged=true: appearance: facing=east,half=top,shape=inner_left,waterlogged=true - id: 45 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=top,shape=inner_right,waterlogged=true: appearance: facing=east,half=top,shape=inner_right,waterlogged=true - id: 46 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=top,shape=outer_left,waterlogged=true: appearance: facing=east,half=top,shape=outer_left,waterlogged=true - id: 47 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=top,shape=outer_right,waterlogged=true: appearance: facing=east,half=top,shape=outer_right,waterlogged=true - id: 48 settings: resistance: 1200.0 burnable: false fluid-state: water facing=east,half=top,shape=straight,waterlogged=true: appearance: facing=east,half=top,shape=straight,waterlogged=true - id: 49 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=bottom,shape=inner_left,waterlogged=true: appearance: facing=north,half=bottom,shape=inner_left,waterlogged=true - id: 50 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=bottom,shape=inner_right,waterlogged=true: appearance: facing=north,half=bottom,shape=inner_right,waterlogged=true - id: 51 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=bottom,shape=outer_left,waterlogged=true: appearance: facing=north,half=bottom,shape=outer_left,waterlogged=true - id: 52 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=bottom,shape=outer_right,waterlogged=true: appearance: facing=north,half=bottom,shape=outer_right,waterlogged=true - id: 53 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=bottom,shape=straight,waterlogged=true: appearance: facing=north,half=bottom,shape=straight,waterlogged=true - id: 54 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=top,shape=inner_left,waterlogged=true: appearance: facing=north,half=top,shape=inner_left,waterlogged=true - id: 55 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=top,shape=inner_right,waterlogged=true: appearance: facing=north,half=top,shape=inner_right,waterlogged=true - id: 56 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=top,shape=outer_left,waterlogged=true: appearance: facing=north,half=top,shape=outer_left,waterlogged=true - id: 57 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=top,shape=outer_right,waterlogged=true: appearance: facing=north,half=top,shape=outer_right,waterlogged=true - id: 58 settings: resistance: 1200.0 burnable: false fluid-state: water facing=north,half=top,shape=straight,waterlogged=true: appearance: facing=north,half=top,shape=straight,waterlogged=true - id: 59 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=bottom,shape=inner_left,waterlogged=true: appearance: facing=south,half=bottom,shape=inner_left,waterlogged=true - id: 60 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=bottom,shape=inner_right,waterlogged=true: appearance: facing=south,half=bottom,shape=inner_right,waterlogged=true - id: 61 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=bottom,shape=outer_left,waterlogged=true: appearance: facing=south,half=bottom,shape=outer_left,waterlogged=true - id: 62 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=bottom,shape=outer_right,waterlogged=true: appearance: facing=south,half=bottom,shape=outer_right,waterlogged=true - id: 63 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=bottom,shape=straight,waterlogged=true: appearance: facing=south,half=bottom,shape=straight,waterlogged=true - id: 64 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=top,shape=inner_left,waterlogged=true: appearance: facing=south,half=top,shape=inner_left,waterlogged=true - id: 65 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=top,shape=inner_right,waterlogged=true: appearance: facing=south,half=top,shape=inner_right,waterlogged=true - id: 66 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=top,shape=outer_left,waterlogged=true: appearance: facing=south,half=top,shape=outer_left,waterlogged=true - id: 67 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=top,shape=outer_right,waterlogged=true: appearance: facing=south,half=top,shape=outer_right,waterlogged=true - id: 68 settings: resistance: 1200.0 burnable: false fluid-state: water facing=south,half=top,shape=straight,waterlogged=true: appearance: facing=south,half=top,shape=straight,waterlogged=true - id: 69 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=bottom,shape=inner_left,waterlogged=true: appearance: facing=west,half=bottom,shape=inner_left,waterlogged=true - id: 70 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=bottom,shape=inner_right,waterlogged=true: appearance: facing=west,half=bottom,shape=inner_right,waterlogged=true - id: 71 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=bottom,shape=outer_left,waterlogged=true: appearance: facing=west,half=bottom,shape=outer_left,waterlogged=true - id: 72 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=bottom,shape=outer_right,waterlogged=true: appearance: facing=west,half=bottom,shape=outer_right,waterlogged=true - id: 73 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=bottom,shape=straight,waterlogged=true: appearance: facing=west,half=bottom,shape=straight,waterlogged=true - id: 74 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=top,shape=inner_left,waterlogged=true: appearance: facing=west,half=top,shape=inner_left,waterlogged=true - id: 75 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=top,shape=inner_right,waterlogged=true: appearance: facing=west,half=top,shape=inner_right,waterlogged=true - id: 76 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=top,shape=outer_left,waterlogged=true: appearance: facing=west,half=top,shape=outer_left,waterlogged=true - id: 77 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=top,shape=outer_right,waterlogged=true: appearance: facing=west,half=top,shape=outer_right,waterlogged=true - id: 78 settings: resistance: 1200.0 burnable: false fluid-state: water facing=west,half=top,shape=straight,waterlogged=true: appearance: facing=west,half=top,shape=straight,waterlogged=true - id: 79 settings: resistance: 1200.0 burnable: false @@ -3144,10 +2867,8 @@ templates#block_states: variants: powered=false: appearance: normal - id: ${normal_id} powered=true: appearance: powered - id: ${powered_id} default:block_state/button: properties: powered: @@ -3329,76 +3050,52 @@ templates#block_states: variants: face=floor,facing=east,powered=true: appearance: face=floor,facing=east,powered=true - id: ${internal_id} face=floor,facing=west,powered=true: appearance: face=floor,facing=west,powered=true - id: ${internal_id} face=floor,facing=east,powered=false: appearance: face=floor,facing=east,powered=false - id: ${internal_id} face=floor,facing=west,powered=false: appearance: face=floor,facing=west,powered=false - id: ${internal_id} face=floor,facing=south,powered=true: appearance: face=floor,facing=south,powered=true - id: ${internal_id} face=floor,facing=north,powered=true: appearance: face=floor,facing=north,powered=true - id: ${internal_id} face=floor,facing=south,powered=false: appearance: face=floor,facing=south,powered=false - id: ${internal_id} face=floor,facing=north,powered=false: appearance: face=floor,facing=north,powered=false - id: ${internal_id} face=wall,facing=north,powered=true: appearance: face=wall,facing=north,powered=true - id: ${internal_id} face=wall,facing=south,powered=true: appearance: face=wall,facing=south,powered=true - id: ${internal_id} face=wall,facing=north,powered=false: appearance: face=wall,facing=north,powered=false - id: ${internal_id} face=wall,facing=south,powered=false: appearance: face=wall,facing=south,powered=false - id: ${internal_id} face=wall,facing=west,powered=true: appearance: face=wall,facing=west,powered=true - id: ${internal_id} face=wall,facing=east,powered=true: appearance: face=wall,facing=east,powered=true - id: ${internal_id} face=wall,facing=west,powered=false: appearance: face=wall,facing=west,powered=false - id: ${internal_id} face=wall,facing=east,powered=false: appearance: face=wall,facing=east,powered=false - id: ${internal_id} face=ceiling,facing=north,powered=true: appearance: face=ceiling,facing=north,powered=true - id: ${internal_id} face=ceiling,facing=south,powered=true: appearance: face=ceiling,facing=south,powered=true - id: ${internal_id} face=ceiling,facing=north,powered=false: appearance: face=ceiling,facing=north,powered=false - id: ${internal_id} face=ceiling,facing=south,powered=false: appearance: face=ceiling,facing=south,powered=false - id: ${internal_id} face=ceiling,facing=west,powered=true: appearance: face=ceiling,facing=west,powered=true - id: ${internal_id} face=ceiling,facing=east,powered=true: appearance: face=ceiling,facing=east,powered=true - id: ${internal_id} face=ceiling,facing=west,powered=false: appearance: face=ceiling,facing=west,powered=false - id: ${internal_id} face=ceiling,facing=east,powered=false: appearance: face=ceiling,facing=east,powered=false - id: ${internal_id} default:block_state/fence: properties: north: @@ -3772,160 +3469,128 @@ templates#block_states: variants: east=false,north=false,south=false,waterlogged=false,west=false: appearance: east=false,north=false,south=false,waterlogged=false,west=false - id: ${internal_id} east=true,north=false,south=false,waterlogged=false,west=false: appearance: east=true,north=false,south=false,waterlogged=false,west=false - id: ${internal_id} east=false,north=true,south=false,waterlogged=false,west=false: appearance: east=false,north=true,south=false,waterlogged=false,west=false - id: ${internal_id} east=false,north=false,south=true,waterlogged=false,west=false: appearance: east=false,north=false,south=true,waterlogged=false,west=false - id: ${internal_id} east=false,north=false,south=false,waterlogged=false,west=true: appearance: east=false,north=false,south=false,waterlogged=false,west=true - id: ${internal_id} east=true,north=true,south=false,waterlogged=false,west=false: appearance: east=true,north=true,south=false,waterlogged=false,west=false - id: ${internal_id} east=true,north=false,south=true,waterlogged=false,west=false: appearance: east=true,north=false,south=true,waterlogged=false,west=false - id: ${internal_id} east=true,north=false,south=false,waterlogged=false,west=true: appearance: east=true,north=false,south=false,waterlogged=false,west=true - id: ${internal_id} east=false,north=true,south=true,waterlogged=false,west=false: appearance: east=false,north=true,south=true,waterlogged=false,west=false - id: ${internal_id} east=false,north=true,south=false,waterlogged=false,west=true: appearance: east=false,north=true,south=false,waterlogged=false,west=true - id: ${internal_id} east=false,north=false,south=true,waterlogged=false,west=true: appearance: east=false,north=false,south=true,waterlogged=false,west=true - id: ${internal_id} east=true,north=true,south=true,waterlogged=false,west=false: appearance: east=true,north=true,south=true,waterlogged=false,west=false - id: ${internal_id} east=true,north=true,south=false,waterlogged=false,west=true: appearance: east=true,north=true,south=false,waterlogged=false,west=true - id: ${internal_id} east=true,north=false,south=true,waterlogged=false,west=true: appearance: east=true,north=false,south=true,waterlogged=false,west=true - id: ${internal_id} east=false,north=true,south=true,waterlogged=false,west=true: appearance: east=false,north=true,south=true,waterlogged=false,west=true - id: ${internal_id} east=true,north=true,south=true,waterlogged=false,west=true: appearance: east=true,north=true,south=true,waterlogged=false,west=true - id: ${internal_id} east=false,north=false,south=false,waterlogged=true,west=false: appearance: east=false,north=false,south=false,waterlogged=true,west=false - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=true,north=false,south=false,waterlogged=true,west=false: appearance: east=true,north=false,south=false,waterlogged=true,west=false - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=false,north=true,south=false,waterlogged=true,west=false: appearance: east=false,north=true,south=false,waterlogged=true,west=false - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=false,north=false,south=true,waterlogged=true,west=false: appearance: east=false,north=false,south=true,waterlogged=true,west=false - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=false,north=false,south=false,waterlogged=true,west=true: appearance: east=false,north=false,south=false,waterlogged=true,west=true - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=true,north=true,south=false,waterlogged=true,west=false: appearance: east=true,north=true,south=false,waterlogged=true,west=false - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=true,north=false,south=true,waterlogged=true,west=false: appearance: east=true,north=false,south=true,waterlogged=true,west=false - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=true,north=false,south=false,waterlogged=true,west=true: appearance: east=true,north=false,south=false,waterlogged=true,west=true - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=false,north=true,south=true,waterlogged=true,west=false: appearance: east=false,north=true,south=true,waterlogged=true,west=false - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=false,north=true,south=false,waterlogged=true,west=true: appearance: east=false,north=true,south=false,waterlogged=true,west=true - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=false,north=false,south=true,waterlogged=true,west=true: appearance: east=false,north=false,south=true,waterlogged=true,west=true - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=true,north=true,south=true,waterlogged=true,west=false: appearance: east=true,north=true,south=true,waterlogged=true,west=false - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=true,north=true,south=false,waterlogged=true,west=true: appearance: east=true,north=true,south=false,waterlogged=true,west=true - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=true,north=false,south=true,waterlogged=true,west=true: appearance: east=true,north=false,south=true,waterlogged=true,west=true - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=false,north=true,south=true,waterlogged=true,west=true: appearance: east=false,north=true,south=true,waterlogged=true,west=true - id: ${internal_id} settings: resistance: 1200.0 burnable: false fluid-state: water east=true,north=true,south=true,waterlogged=true,west=true: appearance: east=true,north=true,south=true,waterlogged=true,west=true - id: ${internal_id} settings: resistance: 1200.0 burnable: false diff --git a/common-files/src/main/resources/resources/internal/configuration/gui.yml b/common-files/src/main/resources/resources/internal/configuration/gui.yml index 344d37d55..42c53dee6 100644 --- a/common-files/src/main/resources/resources/internal/configuration/gui.yml +++ b/common-files/src/main/resources/resources/internal/configuration/gui.yml @@ -74,7 +74,6 @@ images: templates: internal:icon/2d: material: arrow - custom-model-data: ${model_data} data: item-name: ${name} lore: ${lore} @@ -93,7 +92,6 @@ items: internal:next_page_0: template: internal:icon/2d arguments: - model_data: 1000 texture: next_page_0 name: <#FAFAD2> lore: @@ -101,7 +99,6 @@ items: internal:next_page_1: template: internal:icon/2d arguments: - model_data: 1001 texture: next_page_1 name: <#808080> lore: @@ -109,7 +106,6 @@ items: internal:previous_page_0: template: internal:icon/2d arguments: - model_data: 1002 texture: previous_page_0 name: <#FAFAD2> lore: @@ -117,7 +113,6 @@ items: internal:previous_page_1: template: internal:icon/2d arguments: - model_data: 1003 texture: previous_page_1 name: <#808080> lore: @@ -125,34 +120,29 @@ items: internal:return: template: internal:icon/2d arguments: - model_data: 1004 texture: return name: <#DAA520> lore: null internal:next_recipe_0: material: arrow - custom-model-data: 1000 data: item-name: <#FAFAD2> lore: - <#F5F5F5>/ internal:next_recipe_1: material: arrow - custom-model-data: 1001 data: item-name: <#808080> lore: - <#696969>/ internal:previous_recipe_0: material: arrow - custom-model-data: 1002 data: item-name: <#FAFAD2> lore: - <#F5F5F5>/ internal:previous_recipe_1: material: arrow - custom-model-data: 1003 data: item-name: <#808080> lore: @@ -160,7 +150,6 @@ items: internal:get_item: template: internal:icon/2d arguments: - model_data: 1005 texture: get_item name: <#DAA520> lore: @@ -169,7 +158,6 @@ items: internal:cooking_info: template: internal:icon/2d arguments: - model_data: 1006 texture: cooking_info name: <#FF8C00> lore: @@ -178,7 +166,6 @@ items: internal:exit: template: internal:icon/2d arguments: - model_data: 1007 texture: exit name: <#DAA520> lore: null \ No newline at end of file diff --git a/common-files/src/main/resources/resources/internal/configuration/mappings.yml b/common-files/src/main/resources/resources/internal/configuration/mappings.yml new file mode 100644 index 000000000..c113c0d3b --- /dev/null +++ b/common-files/src/main/resources/resources/internal/configuration/mappings.yml @@ -0,0 +1,4451 @@ +# This is one of the plugin's core settings - it basically controls how many block states you can use in your config files. +# Below is the default setup - feel free to add or remove stuff as needed. +block-state-mappings: + #### Anvil #### + # An anvil has four possible orientations, but the east-west and north-south orientations look exactly the same. + minecraft:anvil[facing=north]: minecraft:anvil[facing=south] + minecraft:anvil[facing=east]: minecraft:anvil[facing=west] + minecraft:chipped_anvil[facing=north]: minecraft:chipped_anvil[facing=south] + minecraft:chipped_anvil[facing=east]: minecraft:chipped_anvil[facing=west] + minecraft:damaged_anvil[facing=north]: minecraft:damaged_anvil[facing=south] + minecraft:damaged_anvil[facing=east]: minecraft:damaged_anvil[facing=west] + + #### Sapling #### + # Every sapling has two stages, 0 and 1, but they look exactly the same. + minecraft:oak_sapling[stage=1]: minecraft:oak_sapling[stage=0] + minecraft:birch_sapling[stage=1]: minecraft:birch_sapling[stage=0] + minecraft:spruce_sapling[stage=1]: minecraft:spruce_sapling[stage=0] + minecraft:jungle_sapling[stage=1]: minecraft:jungle_sapling[stage=0] + minecraft:dark_oak_sapling[stage=1]: minecraft:dark_oak_sapling[stage=0] + minecraft:acacia_sapling[stage=1]: minecraft:acacia_sapling[stage=0] + minecraft:cherry_sapling[stage=1]: minecraft:cherry_sapling[stage=0] + $$>=1.21.4#sapling: + minecraft:pale_oak_sapling[stage=1]: minecraft:pale_oak_sapling[stage=0] + + #### Sculk Sensor #### + # The Sculk Sensor's hitbox is exactly half a block. Plus, its appearance only changes based on the sculk_sensor_phase, + # not the power level. That means we can repurpose the extra states to make bottom-half slabs + minecraft:sculk_sensor[power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:sculk_sensor[power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:sculk_sensor[power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:sculk_sensor[power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:sculk_sensor[power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:sculk_sensor[power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:sculk_sensor[power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:sculk_sensor[power=0,sculk_sensor_phase=cooldown,waterlogged=true] + + #### Calibrated Sculk Sensor #### + # Just like the regular Sculk Sensor, but the Calibrated Sculk Sensor has directional facing - which gives us way more usable states to play with + minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=north,power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=north,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=west,power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=west,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=east,power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=east,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=inactive,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=active,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=cooldown,waterlogged=false]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=false] + minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=inactive,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=inactive,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=active,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=active,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=1,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=2,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=3,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=4,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=5,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=6,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=7,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=8,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=9,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=10,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=11,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=12,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=13,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=14,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + minecraft:calibrated_sculk_sensor[facing=south,power=15,sculk_sensor_phase=cooldown,waterlogged=true]: minecraft:calibrated_sculk_sensor[facing=south,power=0,sculk_sensor_phase=cooldown,waterlogged=true] + + #### Mushroom #### + # Most people probably don't mind that mushroom blocks look the same on all six sides. So that means each type can free up like, 63 different states we could use for other stuff + minecraft:mushroom_stem[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:mushroom_stem[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:mushroom_stem[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:brown_mushroom_block[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:brown_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + minecraft:red_mushroom_block[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:red_mushroom_block[down=true,east=true,north=true,south=true,up=true,west=true] + + #### Kelp #### + # 'kelp' here means specifically the top block of the kelp plant. Great for making aquatic crops. + minecraft:kelp[age=1]: minecraft:kelp[age=0] + minecraft:kelp[age=2]: minecraft:kelp[age=0] + minecraft:kelp[age=3]: minecraft:kelp[age=0] + minecraft:kelp[age=4]: minecraft:kelp[age=0] + minecraft:kelp[age=5]: minecraft:kelp[age=0] + minecraft:kelp[age=6]: minecraft:kelp[age=0] + minecraft:kelp[age=7]: minecraft:kelp[age=0] + minecraft:kelp[age=8]: minecraft:kelp[age=0] + minecraft:kelp[age=9]: minecraft:kelp[age=0] + minecraft:kelp[age=10]: minecraft:kelp[age=0] + minecraft:kelp[age=11]: minecraft:kelp[age=0] + minecraft:kelp[age=12]: minecraft:kelp[age=0] + minecraft:kelp[age=13]: minecraft:kelp[age=0] + minecraft:kelp[age=14]: minecraft:kelp[age=0] + minecraft:kelp[age=15]: minecraft:kelp[age=0] + minecraft:kelp[age=16]: minecraft:kelp[age=0] + minecraft:kelp[age=17]: minecraft:kelp[age=0] + minecraft:kelp[age=18]: minecraft:kelp[age=0] + minecraft:kelp[age=19]: minecraft:kelp[age=0] + minecraft:kelp[age=20]: minecraft:kelp[age=0] + minecraft:kelp[age=21]: minecraft:kelp[age=0] + minecraft:kelp[age=22]: minecraft:kelp[age=0] + minecraft:kelp[age=23]: minecraft:kelp[age=0] + minecraft:kelp[age=24]: minecraft:kelp[age=0] + minecraft:kelp[age=25]: minecraft:kelp[age=0] + + #### Vines #### + # Unless you tweak the vine's block tag, the client will always think it's climbable. + # Since vines look identical at different growth stages, we can repurpose those extra states to make custom blocks like ropes. + minecraft:weeping_vines[age=1]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=2]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=3]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=4]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=5]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=6]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=7]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=8]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=9]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=10]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=11]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=12]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=13]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=14]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=15]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=16]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=17]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=18]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=19]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=20]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=21]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=22]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=23]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=24]: minecraft:weeping_vines[age=0] + minecraft:weeping_vines[age=25]: minecraft:weeping_vines[age=0] + minecraft:twisting_vines[age=1]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=2]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=3]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=4]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=5]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=6]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=7]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=8]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=9]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=10]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=11]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=12]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=13]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=14]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=15]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=16]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=17]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=18]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=19]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=20]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=21]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=22]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=23]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=24]: minecraft:twisting_vines[age=0] + minecraft:twisting_vines[age=25]: minecraft:twisting_vines[age=0] + minecraft:cave_vines[age=1,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=2,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=3,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=4,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=5,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=6,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=7,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=8,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=9,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=10,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=11,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=12,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=13,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=14,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=15,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=16,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=17,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=18,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=19,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=20,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=21,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=22,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=23,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=24,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=25,berries=false]: minecraft:cave_vines[age=0,berries=false] + minecraft:cave_vines[age=1,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=2,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=3,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=4,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=5,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=6,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=7,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=8,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=9,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=10,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=11,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=12,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=13,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=14,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=15,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=16,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=17,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=18,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=19,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=20,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=21,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=22,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=23,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=24,berries=true]: minecraft:cave_vines[age=0,berries=true] + minecraft:cave_vines[age=25,berries=true]: minecraft:cave_vines[age=0,berries=true] + + #### SugarCane #### + # Sugar cane looks exactly the same no matter its growth stage. Plus, it's got this perfect hitbox that makes it awesome for taller plants + minecraft:sugar_cane[age=1]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=2]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=3]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=4]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=5]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=6]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=7]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=8]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=9]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=10]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=11]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=12]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=13]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=14]: minecraft:sugar_cane[age=0] + minecraft:sugar_cane[age=15]: minecraft:sugar_cane[age=0] + + #### Cactus #### + # Cactus looks the same at all growth stages.Its hitbox is 14x14x15, making it perfect for creating blocks that are just slightly smaller than full-size + minecraft:cactus[age=1]: minecraft:cactus[age=0] + minecraft:cactus[age=2]: minecraft:cactus[age=0] + minecraft:cactus[age=3]: minecraft:cactus[age=0] + minecraft:cactus[age=4]: minecraft:cactus[age=0] + minecraft:cactus[age=5]: minecraft:cactus[age=0] + minecraft:cactus[age=6]: minecraft:cactus[age=0] + minecraft:cactus[age=7]: minecraft:cactus[age=0] + minecraft:cactus[age=8]: minecraft:cactus[age=0] + minecraft:cactus[age=9]: minecraft:cactus[age=0] + minecraft:cactus[age=10]: minecraft:cactus[age=0] + minecraft:cactus[age=11]: minecraft:cactus[age=0] + minecraft:cactus[age=12]: minecraft:cactus[age=0] + minecraft:cactus[age=13]: minecraft:cactus[age=0] + minecraft:cactus[age=14]: minecraft:cactus[age=0] + minecraft:cactus[age=15]: minecraft:cactus[age=0] + + #### Leaves #### + # The 'distance' and 'persistent' properties are used under the hood to optimize how leaves decay, but visually? They look exactly the same. + # These are some of the few block types that actually support transparent textures. + minecraft:oak_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:oak_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:oak_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:acacia_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:acacia_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:acacia_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:jungle_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:jungle_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:jungle_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:birch_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:birch_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:birch_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:mangrove_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:mangrove_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:mangrove_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:cherry_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:cherry_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:cherry_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:dark_oak_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:dark_oak_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:dark_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:azalea_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:azalea_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:flowering_azalea_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:flowering_azalea_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:flowering_azalea_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:spruce_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:spruce_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:spruce_leaves[distance=7,persistent=true,waterlogged=true] + + $$>=1.21.4#leaves: + minecraft:pale_oak_leaves[distance=1,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=2,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=3,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=4,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=5,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=6,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=7,persistent=false,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=1,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=2,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=3,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=4,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=5,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=6,persistent=true,waterlogged=false]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=false] + minecraft:pale_oak_leaves[distance=1,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=2,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=3,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=4,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=5,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=6,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=7,persistent=false,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=1,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=2,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=3,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=4,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=5,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + minecraft:pale_oak_leaves[distance=6,persistent=true,waterlogged=true]: minecraft:pale_oak_leaves[distance=7,persistent=true,waterlogged=true] + + #### Tripwire #### + # Tripwires actually have 128 different states, but we're keeping just two of them to match vanilla's visual styles. + # Honestly, as long as the tripwire works properly, most players won't even mind what it looks like. + # Tripwire hitboxes aren't all the same - the triggered ones are way shorter. + minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=false,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=false,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=false,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=false]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=false,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=false,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=false,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=true,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=true,north=false,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=false,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=false,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=true,east=false,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=true,east=false,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=false,disarmed=false,east=true,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=false,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + minecraft:tripwire[attached=true,disarmed=false,east=true,north=true,south=true,west=true,powered=true]: minecraft:tripwire[attached=true,disarmed=true,east=true,north=true,south=true,west=true,powered=true] + + #### Note Block #### + # This block has the most unused states in Minecraft, but the client always thinks it's interactive. + # Plus, there's some visual glitches when the client try predicting instrument changes. + # We've kept a full set of note settings by default - that way it plays nice with resource packs that show notes + minecraft:note_block[instrument=hat,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=hat,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=hat,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=hat,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=hat,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=hat,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=hat,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=hat,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=hat,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=hat,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=hat,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=hat,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=hat,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=hat,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=hat,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=hat,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=hat,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=hat,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=hat,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=hat,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=hat,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=hat,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=hat,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=hat,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=hat,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=hat,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=hat,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=hat,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=hat,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=hat,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=hat,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=hat,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=hat,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=hat,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=hat,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=hat,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=hat,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=hat,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=hat,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=hat,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=hat,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=hat,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=hat,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=hat,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=hat,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=hat,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=hat,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=hat,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=hat,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=hat,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=basedrum,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=basedrum,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=basedrum,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=basedrum,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=basedrum,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=basedrum,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=basedrum,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=basedrum,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=basedrum,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=basedrum,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=basedrum,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=basedrum,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=basedrum,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=basedrum,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=basedrum,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=basedrum,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=basedrum,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=basedrum,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=basedrum,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=basedrum,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=basedrum,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=basedrum,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=basedrum,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=basedrum,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=basedrum,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=basedrum,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=basedrum,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=basedrum,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=basedrum,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=basedrum,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=basedrum,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=basedrum,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=basedrum,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=basedrum,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=basedrum,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=basedrum,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=basedrum,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=basedrum,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=basedrum,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=basedrum,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=basedrum,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=basedrum,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=basedrum,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=basedrum,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=basedrum,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=basedrum,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=basedrum,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=basedrum,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=basedrum,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=basedrum,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=snare,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=snare,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=snare,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=snare,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=snare,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=snare,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=snare,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=snare,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=snare,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=snare,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=snare,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=snare,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=snare,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=snare,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=snare,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=snare,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=snare,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=snare,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=snare,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=snare,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=snare,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=snare,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=snare,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=snare,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=snare,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=snare,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=snare,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=snare,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=snare,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=snare,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=snare,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=snare,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=snare,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=snare,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=snare,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=snare,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=snare,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=snare,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=snare,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=snare,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=snare,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=snare,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=snare,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=snare,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=snare,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=snare,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=snare,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=snare,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=snare,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=snare,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=bass,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=bass,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=bass,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=bass,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=bass,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=bass,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=bass,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=bass,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=bass,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=bass,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=bass,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=bass,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=bass,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=bass,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=bass,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=bass,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=bass,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=bass,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=bass,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=bass,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=bass,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=bass,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=bass,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=bass,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=bass,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=bass,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=bass,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=bass,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=bass,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=bass,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=bass,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=bass,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=bass,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=bass,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=bass,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=bass,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=bass,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=bass,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=bass,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=bass,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=bass,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=bass,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=bass,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=bass,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=bass,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=bass,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=bass,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=bass,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=bass,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=bass,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=flute,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=flute,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=flute,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=flute,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=flute,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=flute,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=flute,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=flute,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=flute,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=flute,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=flute,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=flute,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=flute,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=flute,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=flute,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=flute,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=flute,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=flute,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=flute,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=flute,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=flute,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=flute,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=flute,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=flute,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=flute,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=flute,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=flute,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=flute,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=flute,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=flute,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=flute,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=flute,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=flute,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=flute,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=flute,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=flute,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=flute,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=flute,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=flute,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=flute,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=flute,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=flute,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=flute,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=flute,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=flute,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=flute,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=flute,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=flute,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=flute,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=flute,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=bell,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=bell,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=bell,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=bell,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=bell,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=bell,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=bell,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=bell,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=bell,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=bell,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=bell,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=bell,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=bell,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=bell,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=bell,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=bell,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=bell,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=bell,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=bell,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=bell,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=bell,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=bell,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=bell,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=bell,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=bell,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=bell,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=bell,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=bell,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=bell,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=bell,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=bell,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=bell,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=bell,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=bell,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=bell,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=bell,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=bell,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=bell,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=bell,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=bell,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=bell,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=bell,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=bell,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=bell,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=bell,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=bell,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=bell,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=bell,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=bell,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=bell,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=guitar,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=guitar,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=guitar,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=guitar,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=guitar,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=guitar,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=guitar,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=guitar,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=guitar,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=guitar,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=guitar,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=guitar,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=guitar,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=guitar,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=guitar,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=guitar,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=guitar,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=guitar,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=guitar,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=guitar,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=guitar,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=guitar,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=guitar,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=guitar,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=guitar,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=guitar,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=guitar,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=guitar,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=guitar,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=guitar,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=guitar,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=guitar,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=guitar,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=guitar,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=guitar,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=guitar,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=guitar,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=guitar,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=guitar,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=guitar,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=guitar,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=guitar,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=guitar,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=guitar,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=guitar,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=guitar,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=guitar,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=guitar,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=guitar,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=guitar,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=chime,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=chime,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=chime,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=chime,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=chime,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=chime,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=chime,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=chime,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=chime,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=chime,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=chime,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=chime,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=chime,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=chime,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=chime,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=chime,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=chime,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=chime,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=chime,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=chime,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=chime,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=chime,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=chime,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=chime,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=chime,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=chime,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=chime,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=chime,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=chime,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=chime,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=chime,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=chime,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=chime,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=chime,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=chime,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=chime,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=chime,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=chime,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=chime,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=chime,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=chime,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=chime,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=chime,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=chime,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=chime,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=chime,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=chime,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=chime,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=chime,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=chime,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=xylophone,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=xylophone,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=xylophone,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=xylophone,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=xylophone,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=xylophone,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=xylophone,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=xylophone,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=xylophone,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=xylophone,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=xylophone,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=xylophone,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=xylophone,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=xylophone,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=xylophone,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=xylophone,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=xylophone,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=xylophone,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=xylophone,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=xylophone,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=xylophone,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=xylophone,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=xylophone,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=xylophone,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=xylophone,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=xylophone,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=xylophone,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=xylophone,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=xylophone,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=xylophone,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=xylophone,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=xylophone,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=xylophone,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=xylophone,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=xylophone,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=xylophone,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=xylophone,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=xylophone,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=xylophone,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=xylophone,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=xylophone,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=xylophone,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=xylophone,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=xylophone,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=xylophone,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=xylophone,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=xylophone,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=xylophone,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=xylophone,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=xylophone,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=iron_xylophone,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=iron_xylophone,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=cow_bell,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=cow_bell,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=cow_bell,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=cow_bell,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=cow_bell,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=cow_bell,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=cow_bell,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=cow_bell,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=cow_bell,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=cow_bell,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=cow_bell,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=cow_bell,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=cow_bell,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=cow_bell,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=cow_bell,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=cow_bell,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=cow_bell,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=cow_bell,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=cow_bell,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=cow_bell,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=cow_bell,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=cow_bell,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=cow_bell,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=cow_bell,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=cow_bell,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=cow_bell,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=cow_bell,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=cow_bell,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=cow_bell,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=cow_bell,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=cow_bell,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=cow_bell,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=cow_bell,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=cow_bell,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=cow_bell,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=cow_bell,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=cow_bell,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=cow_bell,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=cow_bell,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=cow_bell,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=cow_bell,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=cow_bell,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=cow_bell,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=cow_bell,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=cow_bell,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=cow_bell,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=cow_bell,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=cow_bell,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=cow_bell,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=cow_bell,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=didgeridoo,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=didgeridoo,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=didgeridoo,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=didgeridoo,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=didgeridoo,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=didgeridoo,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=didgeridoo,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=didgeridoo,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=didgeridoo,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=didgeridoo,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=didgeridoo,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=didgeridoo,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=didgeridoo,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=didgeridoo,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=didgeridoo,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=didgeridoo,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=didgeridoo,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=didgeridoo,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=didgeridoo,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=didgeridoo,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=didgeridoo,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=didgeridoo,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=didgeridoo,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=didgeridoo,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=didgeridoo,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=didgeridoo,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=didgeridoo,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=didgeridoo,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=didgeridoo,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=didgeridoo,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=didgeridoo,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=didgeridoo,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=didgeridoo,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=didgeridoo,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=didgeridoo,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=didgeridoo,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=didgeridoo,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=didgeridoo,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=didgeridoo,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=didgeridoo,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=didgeridoo,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=didgeridoo,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=didgeridoo,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=didgeridoo,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=didgeridoo,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=didgeridoo,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=didgeridoo,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=didgeridoo,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=didgeridoo,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=didgeridoo,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=bit,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=bit,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=bit,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=bit,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=bit,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=bit,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=bit,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=bit,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=bit,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=bit,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=bit,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=bit,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=bit,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=bit,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=bit,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=bit,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=bit,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=bit,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=bit,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=bit,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=bit,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=bit,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=bit,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=bit,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=bit,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=bit,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=bit,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=bit,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=bit,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=bit,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=bit,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=bit,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=bit,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=bit,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=bit,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=bit,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=bit,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=bit,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=bit,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=bit,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=bit,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=bit,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=bit,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=bit,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=bit,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=bit,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=bit,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=bit,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=bit,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=bit,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=banjo,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=banjo,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=banjo,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=banjo,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=banjo,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=banjo,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=banjo,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=banjo,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=banjo,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=banjo,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=banjo,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=banjo,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=banjo,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=banjo,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=banjo,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=banjo,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=banjo,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=banjo,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=banjo,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=banjo,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=banjo,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=banjo,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=banjo,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=banjo,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=banjo,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=banjo,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=banjo,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=banjo,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=banjo,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=banjo,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=banjo,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=banjo,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=banjo,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=banjo,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=banjo,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=banjo,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=banjo,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=banjo,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=banjo,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=banjo,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=banjo,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=banjo,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=banjo,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=banjo,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=banjo,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=banjo,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=banjo,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=banjo,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=banjo,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=banjo,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=pling,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=pling,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=pling,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=pling,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=pling,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=pling,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=pling,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=pling,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=pling,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=pling,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=pling,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=pling,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=pling,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=pling,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=pling,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=pling,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=pling,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=pling,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=pling,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=pling,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=pling,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=pling,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=pling,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=pling,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=pling,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=pling,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=pling,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=pling,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=pling,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=pling,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=pling,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=pling,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=pling,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=pling,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=pling,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=pling,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=pling,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=pling,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=pling,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=pling,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=pling,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=pling,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=pling,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=pling,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=pling,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=pling,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=pling,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=pling,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=pling,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=pling,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=zombie,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=zombie,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=zombie,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=zombie,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=zombie,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=zombie,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=zombie,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=zombie,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=zombie,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=zombie,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=zombie,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=zombie,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=zombie,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=zombie,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=zombie,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=zombie,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=zombie,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=zombie,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=zombie,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=zombie,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=zombie,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=zombie,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=zombie,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=zombie,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=zombie,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=zombie,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=zombie,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=zombie,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=zombie,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=zombie,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=zombie,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=zombie,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=zombie,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=zombie,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=zombie,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=zombie,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=zombie,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=zombie,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=zombie,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=zombie,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=zombie,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=zombie,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=zombie,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=zombie,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=zombie,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=zombie,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=zombie,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=zombie,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=zombie,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=zombie,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=skeleton,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=skeleton,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=skeleton,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=skeleton,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=skeleton,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=skeleton,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=skeleton,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=skeleton,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=skeleton,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=skeleton,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=skeleton,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=skeleton,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=skeleton,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=skeleton,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=skeleton,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=skeleton,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=skeleton,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=skeleton,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=skeleton,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=skeleton,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=skeleton,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=skeleton,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=skeleton,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=skeleton,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=skeleton,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=skeleton,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=skeleton,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=skeleton,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=skeleton,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=skeleton,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=skeleton,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=skeleton,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=skeleton,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=skeleton,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=skeleton,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=skeleton,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=skeleton,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=skeleton,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=skeleton,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=skeleton,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=skeleton,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=skeleton,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=skeleton,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=skeleton,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=skeleton,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=skeleton,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=skeleton,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=skeleton,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=skeleton,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=skeleton,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=creeper,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=creeper,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=creeper,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=creeper,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=creeper,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=creeper,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=creeper,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=creeper,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=creeper,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=creeper,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=creeper,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=creeper,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=creeper,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=creeper,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=creeper,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=creeper,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=creeper,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=creeper,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=creeper,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=creeper,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=creeper,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=creeper,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=creeper,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=creeper,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=creeper,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=creeper,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=creeper,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=creeper,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=creeper,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=creeper,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=creeper,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=creeper,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=creeper,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=creeper,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=creeper,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=creeper,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=creeper,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=creeper,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=creeper,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=creeper,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=creeper,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=creeper,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=creeper,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=creeper,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=creeper,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=creeper,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=creeper,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=creeper,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=creeper,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=creeper,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=dragon,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=dragon,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=dragon,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=dragon,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=dragon,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=dragon,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=dragon,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=dragon,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=dragon,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=dragon,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=dragon,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=dragon,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=dragon,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=dragon,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=dragon,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=dragon,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=dragon,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=dragon,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=dragon,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=dragon,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=dragon,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=dragon,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=dragon,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=dragon,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=dragon,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=dragon,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=dragon,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=dragon,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=dragon,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=dragon,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=dragon,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=dragon,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=dragon,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=dragon,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=dragon,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=dragon,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=dragon,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=dragon,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=dragon,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=dragon,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=dragon,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=dragon,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=dragon,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=dragon,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=dragon,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=dragon,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=dragon,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=dragon,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=dragon,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=dragon,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=wither_skeleton,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=wither_skeleton,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=piglin,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=piglin,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=piglin,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=piglin,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=piglin,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=piglin,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=piglin,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=piglin,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=piglin,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=piglin,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=piglin,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=piglin,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=piglin,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=piglin,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=piglin,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=piglin,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=piglin,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=piglin,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=piglin,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=piglin,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=piglin,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=piglin,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=piglin,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=piglin,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=piglin,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=piglin,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=piglin,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=piglin,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=piglin,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=piglin,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=piglin,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=piglin,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=piglin,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=piglin,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=piglin,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=piglin,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=piglin,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=piglin,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=piglin,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=piglin,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=piglin,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=piglin,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=piglin,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=piglin,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=piglin,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=piglin,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=piglin,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=piglin,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=piglin,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=piglin,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + minecraft:note_block[instrument=custom_head,note=0,powered=false]: minecraft:note_block[instrument=harp,note=0,powered=false] + minecraft:note_block[instrument=custom_head,note=1,powered=false]: minecraft:note_block[instrument=harp,note=1,powered=false] + minecraft:note_block[instrument=custom_head,note=2,powered=false]: minecraft:note_block[instrument=harp,note=2,powered=false] + minecraft:note_block[instrument=custom_head,note=3,powered=false]: minecraft:note_block[instrument=harp,note=3,powered=false] + minecraft:note_block[instrument=custom_head,note=4,powered=false]: minecraft:note_block[instrument=harp,note=4,powered=false] + minecraft:note_block[instrument=custom_head,note=5,powered=false]: minecraft:note_block[instrument=harp,note=5,powered=false] + minecraft:note_block[instrument=custom_head,note=6,powered=false]: minecraft:note_block[instrument=harp,note=6,powered=false] + minecraft:note_block[instrument=custom_head,note=7,powered=false]: minecraft:note_block[instrument=harp,note=7,powered=false] + minecraft:note_block[instrument=custom_head,note=8,powered=false]: minecraft:note_block[instrument=harp,note=8,powered=false] + minecraft:note_block[instrument=custom_head,note=9,powered=false]: minecraft:note_block[instrument=harp,note=9,powered=false] + minecraft:note_block[instrument=custom_head,note=10,powered=false]: minecraft:note_block[instrument=harp,note=10,powered=false] + minecraft:note_block[instrument=custom_head,note=11,powered=false]: minecraft:note_block[instrument=harp,note=11,powered=false] + minecraft:note_block[instrument=custom_head,note=12,powered=false]: minecraft:note_block[instrument=harp,note=12,powered=false] + minecraft:note_block[instrument=custom_head,note=13,powered=false]: minecraft:note_block[instrument=harp,note=13,powered=false] + minecraft:note_block[instrument=custom_head,note=14,powered=false]: minecraft:note_block[instrument=harp,note=14,powered=false] + minecraft:note_block[instrument=custom_head,note=15,powered=false]: minecraft:note_block[instrument=harp,note=15,powered=false] + minecraft:note_block[instrument=custom_head,note=16,powered=false]: minecraft:note_block[instrument=harp,note=16,powered=false] + minecraft:note_block[instrument=custom_head,note=17,powered=false]: minecraft:note_block[instrument=harp,note=17,powered=false] + minecraft:note_block[instrument=custom_head,note=18,powered=false]: minecraft:note_block[instrument=harp,note=18,powered=false] + minecraft:note_block[instrument=custom_head,note=19,powered=false]: minecraft:note_block[instrument=harp,note=19,powered=false] + minecraft:note_block[instrument=custom_head,note=20,powered=false]: minecraft:note_block[instrument=harp,note=20,powered=false] + minecraft:note_block[instrument=custom_head,note=21,powered=false]: minecraft:note_block[instrument=harp,note=21,powered=false] + minecraft:note_block[instrument=custom_head,note=22,powered=false]: minecraft:note_block[instrument=harp,note=22,powered=false] + minecraft:note_block[instrument=custom_head,note=23,powered=false]: minecraft:note_block[instrument=harp,note=23,powered=false] + minecraft:note_block[instrument=custom_head,note=24,powered=false]: minecraft:note_block[instrument=harp,note=24,powered=false] + minecraft:note_block[instrument=custom_head,note=0,powered=true]: minecraft:note_block[instrument=harp,note=0,powered=true] + minecraft:note_block[instrument=custom_head,note=1,powered=true]: minecraft:note_block[instrument=harp,note=1,powered=true] + minecraft:note_block[instrument=custom_head,note=2,powered=true]: minecraft:note_block[instrument=harp,note=2,powered=true] + minecraft:note_block[instrument=custom_head,note=3,powered=true]: minecraft:note_block[instrument=harp,note=3,powered=true] + minecraft:note_block[instrument=custom_head,note=4,powered=true]: minecraft:note_block[instrument=harp,note=4,powered=true] + minecraft:note_block[instrument=custom_head,note=5,powered=true]: minecraft:note_block[instrument=harp,note=5,powered=true] + minecraft:note_block[instrument=custom_head,note=6,powered=true]: minecraft:note_block[instrument=harp,note=6,powered=true] + minecraft:note_block[instrument=custom_head,note=7,powered=true]: minecraft:note_block[instrument=harp,note=7,powered=true] + minecraft:note_block[instrument=custom_head,note=8,powered=true]: minecraft:note_block[instrument=harp,note=8,powered=true] + minecraft:note_block[instrument=custom_head,note=9,powered=true]: minecraft:note_block[instrument=harp,note=9,powered=true] + minecraft:note_block[instrument=custom_head,note=10,powered=true]: minecraft:note_block[instrument=harp,note=10,powered=true] + minecraft:note_block[instrument=custom_head,note=11,powered=true]: minecraft:note_block[instrument=harp,note=11,powered=true] + minecraft:note_block[instrument=custom_head,note=12,powered=true]: minecraft:note_block[instrument=harp,note=12,powered=true] + minecraft:note_block[instrument=custom_head,note=13,powered=true]: minecraft:note_block[instrument=harp,note=13,powered=true] + minecraft:note_block[instrument=custom_head,note=14,powered=true]: minecraft:note_block[instrument=harp,note=14,powered=true] + minecraft:note_block[instrument=custom_head,note=15,powered=true]: minecraft:note_block[instrument=harp,note=15,powered=true] + minecraft:note_block[instrument=custom_head,note=16,powered=true]: minecraft:note_block[instrument=harp,note=16,powered=true] + minecraft:note_block[instrument=custom_head,note=17,powered=true]: minecraft:note_block[instrument=harp,note=17,powered=true] + minecraft:note_block[instrument=custom_head,note=18,powered=true]: minecraft:note_block[instrument=harp,note=18,powered=true] + minecraft:note_block[instrument=custom_head,note=19,powered=true]: minecraft:note_block[instrument=harp,note=19,powered=true] + minecraft:note_block[instrument=custom_head,note=20,powered=true]: minecraft:note_block[instrument=harp,note=20,powered=true] + minecraft:note_block[instrument=custom_head,note=21,powered=true]: minecraft:note_block[instrument=harp,note=21,powered=true] + minecraft:note_block[instrument=custom_head,note=22,powered=true]: minecraft:note_block[instrument=harp,note=22,powered=true] + minecraft:note_block[instrument=custom_head,note=23,powered=true]: minecraft:note_block[instrument=harp,note=23,powered=true] + minecraft:note_block[instrument=custom_head,note=24,powered=true]: minecraft:note_block[instrument=harp,note=24,powered=true] + + #### Trapdoor #### + # Trapdoors look identical whether they're powered or not - which means we can double our trapdoors by using both states + minecraft:iron_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:iron_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:iron_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:iron_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:iron_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:acacia_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:acacia_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:acacia_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:acacia_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:spruce_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:spruce_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:spruce_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:spruce_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:birch_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:birch_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:birch_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:birch_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:jungle_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:jungle_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:jungle_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:jungle_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:dark_oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:mangrove_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:mangrove_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:mangrove_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:mangrove_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:cherry_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:cherry_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:cherry_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:cherry_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:bamboo_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:bamboo_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:bamboo_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:bamboo_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:crimson_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:crimson_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:crimson_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:crimson_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:warped_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:warped_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:warped_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:warped_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + + $$>=1.20.3#trapdoor: + minecraft:copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + # Fun fact: copper blocks look the same whether waxed or not. + # We're playing it safe with the default setup - keeping vanilla's waxed states recognizable. + # But you can always change it to convert waxed blocks back to regular ones. + minecraft:waxed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_exposed_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_weathered_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:waxed_oxidized_copper_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + + $$>=1.21.4#trapdoor: + minecraft:pale_oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=north,half=top,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=north,half=top,open=true,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=south,half=top,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=south,half=top,open=true,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=east,half=top,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=east,half=top,open=true,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=west,half=top,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=west,half=top,open=true,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=north,half=top,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=north,half=top,open=false,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=south,half=top,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=south,half=top,open=false,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=east,half=top,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=east,half=top,open=false,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=west,half=top,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=west,half=top,open=false,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=false]: minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=false] + minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=true,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=true,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=north,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=south,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=east,half=bottom,open=false,powered=false,waterlogged=true] + minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=false,powered=true,waterlogged=true]: minecraft:pale_oak_trapdoor[facing=west,half=bottom,open=false,powered=false,waterlogged=true] + + #### Door #### + # A door look exactly the same whether it's powered on or off, just like how a trapdoor works + minecraft:oak_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:oak_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:oak_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:oak_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:oak_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:oak_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:oak_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:oak_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:oak_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:oak_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:oak_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:oak_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:oak_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:oak_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:oak_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:oak_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:oak_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:oak_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:oak_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:oak_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:oak_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:oak_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:oak_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:oak_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:oak_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:oak_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:oak_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:spruce_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:spruce_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:spruce_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:spruce_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:spruce_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:spruce_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:spruce_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:spruce_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:spruce_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:spruce_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:spruce_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:spruce_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:spruce_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:spruce_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:spruce_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:spruce_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:spruce_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:spruce_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:spruce_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:spruce_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:spruce_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:spruce_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:spruce_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:spruce_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:spruce_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:spruce_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:spruce_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:spruce_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:spruce_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:spruce_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:spruce_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:spruce_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:spruce_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:spruce_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:spruce_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:spruce_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:birch_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:birch_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:birch_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:birch_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:birch_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:birch_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:birch_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:birch_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:birch_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:birch_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:birch_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:birch_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:birch_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:birch_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:birch_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:birch_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:birch_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:birch_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:birch_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:birch_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:birch_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:birch_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:birch_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:birch_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:birch_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:birch_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:birch_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:birch_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:birch_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:birch_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:birch_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:birch_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:birch_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:birch_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:birch_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:birch_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:jungle_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:jungle_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:jungle_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:jungle_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:jungle_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:jungle_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:jungle_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:jungle_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:jungle_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:jungle_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:jungle_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:jungle_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:jungle_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:jungle_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:jungle_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:jungle_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:jungle_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:jungle_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:jungle_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:jungle_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:jungle_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:jungle_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:jungle_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:jungle_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:jungle_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:jungle_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:jungle_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:jungle_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:jungle_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:jungle_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:jungle_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:jungle_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:jungle_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:jungle_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:jungle_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:jungle_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:acacia_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:acacia_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:acacia_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:acacia_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:acacia_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:acacia_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:acacia_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:acacia_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:acacia_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:acacia_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:acacia_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:acacia_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:acacia_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:acacia_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:acacia_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:acacia_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:acacia_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:acacia_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:acacia_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:acacia_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:acacia_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:acacia_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:acacia_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:acacia_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:acacia_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:acacia_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:acacia_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:acacia_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:acacia_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:acacia_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:acacia_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:acacia_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:acacia_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:acacia_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:acacia_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:acacia_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:dark_oak_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:dark_oak_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:dark_oak_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:dark_oak_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:dark_oak_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:dark_oak_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:dark_oak_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:dark_oak_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:dark_oak_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:dark_oak_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:dark_oak_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:dark_oak_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:dark_oak_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:dark_oak_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:dark_oak_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:dark_oak_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:dark_oak_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:dark_oak_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:dark_oak_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:dark_oak_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:dark_oak_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:dark_oak_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:mangrove_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:mangrove_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:mangrove_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:mangrove_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:mangrove_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:mangrove_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:mangrove_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:mangrove_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:mangrove_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:mangrove_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:mangrove_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:mangrove_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:mangrove_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:mangrove_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:mangrove_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:mangrove_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:mangrove_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:mangrove_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:mangrove_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:mangrove_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:mangrove_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:mangrove_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:mangrove_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:mangrove_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:mangrove_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:mangrove_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:mangrove_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:mangrove_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:mangrove_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:mangrove_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:mangrove_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:mangrove_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:mangrove_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:mangrove_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:mangrove_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:mangrove_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:cherry_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:cherry_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:cherry_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:cherry_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:cherry_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:cherry_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:cherry_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:cherry_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:cherry_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:cherry_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:cherry_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:cherry_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:cherry_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:cherry_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:cherry_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:cherry_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:cherry_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:cherry_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:cherry_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:cherry_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:cherry_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:cherry_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:cherry_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:cherry_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:cherry_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:cherry_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:cherry_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:cherry_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:cherry_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:cherry_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:cherry_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:cherry_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:cherry_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:cherry_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:cherry_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:cherry_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:bamboo_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:bamboo_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:bamboo_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:bamboo_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:bamboo_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:bamboo_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:bamboo_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:bamboo_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:bamboo_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:bamboo_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:bamboo_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:bamboo_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:bamboo_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:bamboo_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:bamboo_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:bamboo_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:bamboo_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:bamboo_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:bamboo_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:bamboo_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:bamboo_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:bamboo_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:bamboo_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:bamboo_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:bamboo_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:bamboo_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:bamboo_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:bamboo_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:bamboo_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:bamboo_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:bamboo_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:bamboo_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:bamboo_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:bamboo_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:bamboo_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:bamboo_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:crimson_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:crimson_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:crimson_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:crimson_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:crimson_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:crimson_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:crimson_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:crimson_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:crimson_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:crimson_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:crimson_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:crimson_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:crimson_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:crimson_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:crimson_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:crimson_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:crimson_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:crimson_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:crimson_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:crimson_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:crimson_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:crimson_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:crimson_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:crimson_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:crimson_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:crimson_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:crimson_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:crimson_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:crimson_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:crimson_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:crimson_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:crimson_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:crimson_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:crimson_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:crimson_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:crimson_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:warped_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:warped_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:warped_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:warped_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:warped_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:warped_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:warped_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:warped_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:warped_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:warped_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:warped_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:warped_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:warped_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:warped_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:warped_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:warped_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:warped_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:warped_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:warped_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:warped_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:warped_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:warped_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:warped_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:warped_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:warped_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:warped_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:warped_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:warped_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:warped_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:warped_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:warped_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:warped_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:warped_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:warped_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:warped_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:warped_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:iron_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:iron_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:iron_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:iron_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:iron_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:iron_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:iron_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:iron_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:iron_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:iron_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:iron_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:iron_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:iron_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:iron_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:iron_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:iron_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:iron_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:iron_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:iron_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:iron_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:iron_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:iron_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:iron_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:iron_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:iron_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:iron_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:iron_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:iron_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:iron_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:iron_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:iron_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:iron_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:iron_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:iron_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:iron_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:iron_door[facing=west,half=upper,hinge=right,open=true,powered=false] + + $$>=1.20.3#door: + minecraft:copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:exposed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:exposed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:exposed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:exposed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:exposed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:exposed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:exposed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:exposed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:exposed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:exposed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:exposed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:exposed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:exposed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:exposed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:exposed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:exposed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:exposed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:exposed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:exposed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:exposed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:exposed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:exposed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:exposed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:exposed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:exposed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:exposed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:exposed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:exposed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:exposed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:exposed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:exposed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:exposed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:exposed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:exposed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:exposed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:exposed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:weathered_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:weathered_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:weathered_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:weathered_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:weathered_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:weathered_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:weathered_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:weathered_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:weathered_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:weathered_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:weathered_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:weathered_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:weathered_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:weathered_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:weathered_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:weathered_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:weathered_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:weathered_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:weathered_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:weathered_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:weathered_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:weathered_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:weathered_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:weathered_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:weathered_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:weathered_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:weathered_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:weathered_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:weathered_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:weathered_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:weathered_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:weathered_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:weathered_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:weathered_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:weathered_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:weathered_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:oxidized_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:oxidized_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:oxidized_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:oxidized_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:oxidized_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:oxidized_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:oxidized_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:oxidized_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:oxidized_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:oxidized_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:oxidized_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:oxidized_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:oxidized_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:oxidized_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:oxidized_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:oxidized_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:oxidized_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:oxidized_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:oxidized_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:oxidized_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:oxidized_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:oxidized_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:oxidized_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:oxidized_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:oxidized_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:oxidized_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:oxidized_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:oxidized_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:oxidized_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:oxidized_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:oxidized_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:oxidized_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:oxidized_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:oxidized_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:oxidized_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:oxidized_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_exposed_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_weathered_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:waxed_oxidized_copper_door[facing=west,half=upper,hinge=right,open=true,powered=false] + + $$>=1.21.4#door: + minecraft:pale_oak_door[facing=east,half=lower,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=east,half=lower,hinge=left,open=false,powered=false] + minecraft:pale_oak_door[facing=east,half=lower,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=east,half=lower,hinge=right,open=false,powered=false] + minecraft:pale_oak_door[facing=east,half=upper,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=east,half=upper,hinge=left,open=false,powered=false] + minecraft:pale_oak_door[facing=east,half=upper,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=east,half=upper,hinge=right,open=false,powered=false] + minecraft:pale_oak_door[facing=east,half=lower,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=east,half=lower,hinge=left,open=true,powered=false] + minecraft:pale_oak_door[facing=east,half=lower,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=east,half=lower,hinge=right,open=true,powered=false] + minecraft:pale_oak_door[facing=east,half=upper,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=east,half=upper,hinge=left,open=true,powered=false] + minecraft:pale_oak_door[facing=east,half=upper,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=east,half=upper,hinge=right,open=true,powered=false] + minecraft:pale_oak_door[facing=north,half=lower,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=north,half=lower,hinge=left,open=false,powered=false] + minecraft:pale_oak_door[facing=north,half=lower,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=north,half=lower,hinge=right,open=false,powered=false] + minecraft:pale_oak_door[facing=north,half=upper,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=north,half=upper,hinge=left,open=false,powered=false] + minecraft:pale_oak_door[facing=north,half=upper,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=north,half=upper,hinge=right,open=false,powered=false] + minecraft:pale_oak_door[facing=north,half=lower,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=north,half=lower,hinge=left,open=true,powered=false] + minecraft:pale_oak_door[facing=north,half=lower,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=north,half=lower,hinge=right,open=true,powered=false] + minecraft:pale_oak_door[facing=north,half=upper,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=north,half=upper,hinge=left,open=true,powered=false] + minecraft:pale_oak_door[facing=north,half=upper,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=north,half=upper,hinge=right,open=true,powered=false] + minecraft:pale_oak_door[facing=south,half=lower,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=south,half=lower,hinge=left,open=false,powered=false] + minecraft:pale_oak_door[facing=south,half=lower,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=south,half=lower,hinge=right,open=false,powered=false] + minecraft:pale_oak_door[facing=south,half=upper,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=south,half=upper,hinge=left,open=false,powered=false] + minecraft:pale_oak_door[facing=south,half=upper,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=south,half=upper,hinge=right,open=false,powered=false] + minecraft:pale_oak_door[facing=south,half=lower,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=south,half=lower,hinge=left,open=true,powered=false] + minecraft:pale_oak_door[facing=south,half=lower,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=south,half=lower,hinge=right,open=true,powered=false] + minecraft:pale_oak_door[facing=south,half=upper,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=south,half=upper,hinge=left,open=true,powered=false] + minecraft:pale_oak_door[facing=south,half=upper,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=south,half=upper,hinge=right,open=true,powered=false] + minecraft:pale_oak_door[facing=west,half=lower,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=west,half=lower,hinge=left,open=false,powered=false] + minecraft:pale_oak_door[facing=west,half=lower,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=west,half=lower,hinge=right,open=false,powered=false] + minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=false,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=false,powered=false] + minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=false,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=false,powered=false] + minecraft:pale_oak_door[facing=west,half=lower,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=lower,hinge=left,open=true,powered=false] + minecraft:pale_oak_door[facing=west,half=lower,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=lower,hinge=right,open=true,powered=false] + minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=left,open=true,powered=false] + minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=true,powered=true]: minecraft:pale_oak_door[facing=west,half=upper,hinge=right,open=true,powered=false] + + #### Fence Gate #### + minecraft:oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:oak_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:oak_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:oak_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:oak_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:oak_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:oak_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:oak_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:oak_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:oak_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:spruce_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:spruce_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:spruce_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:spruce_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:spruce_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:spruce_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:spruce_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:spruce_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:spruce_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:spruce_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:spruce_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:spruce_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:spruce_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:spruce_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:spruce_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:spruce_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:spruce_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:spruce_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:spruce_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:spruce_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:spruce_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:spruce_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:spruce_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:spruce_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:spruce_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:spruce_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:spruce_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:spruce_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:spruce_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:spruce_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:spruce_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:birch_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:birch_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:birch_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:birch_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:birch_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:birch_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:birch_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:birch_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:birch_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:birch_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:birch_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:birch_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:birch_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:birch_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:birch_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:birch_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:birch_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:birch_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:birch_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:birch_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:birch_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:birch_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:birch_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:birch_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:birch_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:birch_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:birch_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:birch_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:birch_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:birch_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:birch_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:jungle_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:jungle_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:jungle_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:jungle_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:jungle_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:jungle_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:jungle_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:jungle_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:jungle_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:jungle_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:jungle_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:jungle_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:jungle_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:jungle_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:jungle_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:jungle_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:jungle_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:jungle_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:jungle_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:jungle_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:jungle_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:jungle_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:jungle_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:jungle_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:jungle_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:jungle_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:jungle_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:jungle_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:jungle_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:jungle_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:jungle_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:acacia_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:acacia_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:acacia_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:acacia_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:acacia_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:acacia_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:acacia_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:acacia_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:acacia_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:acacia_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:acacia_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:acacia_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:acacia_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:acacia_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:acacia_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:acacia_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:acacia_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:acacia_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:acacia_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:acacia_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:acacia_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:acacia_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:acacia_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:acacia_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:acacia_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:acacia_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:acacia_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:acacia_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:acacia_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:acacia_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:acacia_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:dark_oak_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:dark_oak_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:dark_oak_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:dark_oak_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:dark_oak_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:dark_oak_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:dark_oak_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:dark_oak_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:dark_oak_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:dark_oak_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:mangrove_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:mangrove_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:mangrove_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:mangrove_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:mangrove_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:mangrove_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:mangrove_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:mangrove_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:mangrove_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:mangrove_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:mangrove_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:mangrove_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:mangrove_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:mangrove_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:mangrove_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:mangrove_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:mangrove_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:mangrove_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:cherry_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:cherry_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:cherry_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:cherry_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:cherry_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:cherry_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:cherry_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:cherry_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:cherry_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:cherry_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:cherry_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:cherry_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:cherry_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:cherry_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:cherry_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:cherry_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:cherry_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:cherry_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:cherry_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:cherry_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:cherry_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:cherry_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:cherry_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:cherry_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:cherry_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:cherry_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:cherry_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:cherry_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:cherry_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:cherry_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:cherry_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:cherry_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:bamboo_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:bamboo_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:bamboo_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:bamboo_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:bamboo_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:bamboo_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:bamboo_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:bamboo_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:bamboo_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:bamboo_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:bamboo_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:bamboo_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:bamboo_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:bamboo_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:bamboo_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:bamboo_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:bamboo_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:bamboo_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:crimson_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:crimson_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:crimson_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:crimson_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:crimson_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:crimson_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:crimson_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:crimson_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:crimson_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:crimson_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:crimson_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:crimson_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:crimson_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:crimson_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:crimson_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:crimson_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:crimson_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:crimson_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:crimson_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:crimson_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:crimson_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:crimson_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:crimson_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:crimson_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:crimson_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:crimson_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:crimson_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:crimson_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:crimson_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:crimson_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:crimson_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:crimson_fence_gate[facing=north,in_wall=true,open=true,powered=false] + minecraft:warped_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:warped_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:warped_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:warped_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:warped_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:warped_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:warped_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:warped_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:warped_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:warped_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:warped_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:warped_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:warped_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:warped_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:warped_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:warped_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:warped_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:warped_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:warped_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:warped_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:warped_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:warped_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:warped_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:warped_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:warped_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:warped_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:warped_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:warped_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:warped_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:warped_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:warped_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:warped_fence_gate[facing=north,in_wall=true,open=true,powered=false] + + $$>=1.21.4#fence_gate: + minecraft:pale_oak_fence_gate[facing=east,in_wall=false,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=east,in_wall=false,open=false,powered=false] + minecraft:pale_oak_fence_gate[facing=east,in_wall=false,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=east,in_wall=false,open=true,powered=false] + minecraft:pale_oak_fence_gate[facing=east,in_wall=true,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=east,in_wall=true,open=false,powered=false] + minecraft:pale_oak_fence_gate[facing=east,in_wall=true,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=east,in_wall=true,open=true,powered=false] + minecraft:pale_oak_fence_gate[facing=south,in_wall=false,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=south,in_wall=false,open=false,powered=false] + minecraft:pale_oak_fence_gate[facing=south,in_wall=false,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=south,in_wall=false,open=true,powered=false] + minecraft:pale_oak_fence_gate[facing=south,in_wall=true,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=south,in_wall=true,open=false,powered=false] + minecraft:pale_oak_fence_gate[facing=south,in_wall=true,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=south,in_wall=true,open=true,powered=false] + minecraft:pale_oak_fence_gate[facing=west,in_wall=false,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=west,in_wall=false,open=false,powered=false] + minecraft:pale_oak_fence_gate[facing=west,in_wall=false,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=west,in_wall=false,open=true,powered=false] + minecraft:pale_oak_fence_gate[facing=west,in_wall=true,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=west,in_wall=true,open=false,powered=false] + minecraft:pale_oak_fence_gate[facing=west,in_wall=true,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=west,in_wall=true,open=true,powered=false] + minecraft:pale_oak_fence_gate[facing=north,in_wall=false,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=north,in_wall=false,open=false,powered=false] + minecraft:pale_oak_fence_gate[facing=north,in_wall=false,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=north,in_wall=false,open=true,powered=false] + minecraft:pale_oak_fence_gate[facing=north,in_wall=true,open=false,powered=true]: minecraft:pale_oak_fence_gate[facing=north,in_wall=true,open=false,powered=false] + minecraft:pale_oak_fence_gate[facing=north,in_wall=true,open=true,powered=true]: minecraft:pale_oak_fence_gate[facing=north,in_wall=true,open=true,powered=false] + + #### Slab #### + minecraft:petrified_oak_slab[type=bottom,waterlogged=false]: minecraft:oak_slab[type=bottom,waterlogged=false] + minecraft:petrified_oak_slab[type=top,waterlogged=false]: minecraft:oak_slab[type=top,waterlogged=false] + minecraft:petrified_oak_slab[type=double,waterlogged=false]: minecraft:oak_slab[type=double,waterlogged=false] + minecraft:petrified_oak_slab[type=bottom,waterlogged=true]: minecraft:oak_slab[type=bottom,waterlogged=true] + minecraft:petrified_oak_slab[type=top,waterlogged=true]: minecraft:oak_slab[type=top,waterlogged=true] + minecraft:petrified_oak_slab[type=double,waterlogged=true]: minecraft:oak_slab[type=double,waterlogged=true] + minecraft:cut_copper_slab[type=bottom,waterlogged=false]: minecraft:waxed_cut_copper_slab[type=bottom,waterlogged=false] + minecraft:cut_copper_slab[type=top,waterlogged=false]: minecraft:waxed_cut_copper_slab[type=top,waterlogged=false] + minecraft:cut_copper_slab[type=double,waterlogged=false]: minecraft:waxed_cut_copper_slab[type=double,waterlogged=false] + minecraft:cut_copper_slab[type=bottom,waterlogged=true]: minecraft:waxed_cut_copper_slab[type=bottom,waterlogged=true] + minecraft:cut_copper_slab[type=top,waterlogged=true]: minecraft:waxed_cut_copper_slab[type=top,waterlogged=true] + minecraft:cut_copper_slab[type=double,waterlogged=true]: minecraft:waxed_cut_copper_slab[type=double,waterlogged=true] + minecraft:exposed_cut_copper_slab[type=bottom,waterlogged=false]: minecraft:waxed_exposed_cut_copper_slab[type=bottom,waterlogged=false] + minecraft:exposed_cut_copper_slab[type=top,waterlogged=false]: minecraft:waxed_exposed_cut_copper_slab[type=top,waterlogged=false] + minecraft:exposed_cut_copper_slab[type=double,waterlogged=false]: minecraft:waxed_exposed_cut_copper_slab[type=double,waterlogged=false] + minecraft:exposed_cut_copper_slab[type=bottom,waterlogged=true]: minecraft:waxed_exposed_cut_copper_slab[type=bottom,waterlogged=true] + minecraft:exposed_cut_copper_slab[type=top,waterlogged=true]: minecraft:waxed_exposed_cut_copper_slab[type=top,waterlogged=true] + minecraft:exposed_cut_copper_slab[type=double,waterlogged=true]: minecraft:waxed_exposed_cut_copper_slab[type=double,waterlogged=true] + minecraft:weathered_cut_copper_slab[type=bottom,waterlogged=false]: minecraft:waxed_weathered_cut_copper_slab[type=bottom,waterlogged=false] + minecraft:weathered_cut_copper_slab[type=top,waterlogged=false]: minecraft:waxed_weathered_cut_copper_slab[type=top,waterlogged=false] + minecraft:weathered_cut_copper_slab[type=double,waterlogged=false]: minecraft:waxed_weathered_cut_copper_slab[type=double,waterlogged=false] + minecraft:weathered_cut_copper_slab[type=bottom,waterlogged=true]: minecraft:waxed_weathered_cut_copper_slab[type=bottom,waterlogged=true] + minecraft:weathered_cut_copper_slab[type=top,waterlogged=true]: minecraft:waxed_weathered_cut_copper_slab[type=top,waterlogged=true] + minecraft:weathered_cut_copper_slab[type=double,waterlogged=true]: minecraft:waxed_weathered_cut_copper_slab[type=double,waterlogged=true] + minecraft:oxidized_cut_copper_slab[type=bottom,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_slab[type=bottom,waterlogged=false] + minecraft:oxidized_cut_copper_slab[type=top,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_slab[type=top,waterlogged=false] + minecraft:oxidized_cut_copper_slab[type=double,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_slab[type=double,waterlogged=false] + minecraft:oxidized_cut_copper_slab[type=bottom,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_slab[type=bottom,waterlogged=true] + minecraft:oxidized_cut_copper_slab[type=top,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_slab[type=top,waterlogged=true] + minecraft:oxidized_cut_copper_slab[type=double,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_slab[type=double,waterlogged=true] + + #### Stairs #### + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true] + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true] + minecraft:cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true] + minecraft:cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false] + minecraft:cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false] + minecraft:exposed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_exposed_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false] + minecraft:weathered_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_weathered_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=straight,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=inner_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=bottom,shape=outer_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=straight,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=inner_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=east,half=top,shape=outer_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=straight,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=inner_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=bottom,shape=outer_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=straight,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=inner_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=south,half=top,shape=outer_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=straight,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=inner_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=bottom,shape=outer_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=straight,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=inner_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=west,half=top,shape=outer_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=straight,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=inner_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=bottom,shape=outer_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=straight,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=inner_right,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_left,waterlogged=true] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=false] + minecraft:oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true]: minecraft:waxed_oxidized_cut_copper_stairs[facing=north,half=top,shape=outer_right,waterlogged=true] + + #### Grate #### + # Suitable for making glass because it is completely transparent + $$>=1.20.3#grate: + minecraft:copper_grate[waterlogged=false]: minecraft:waxed_copper_grate[waterlogged=false] + minecraft:copper_grate[waterlogged=true]: minecraft:waxed_copper_grate[waterlogged=true] + minecraft:weathered_copper_grate[waterlogged=false]: minecraft:waxed_weathered_copper_grate[waterlogged=false] + minecraft:weathered_copper_grate[waterlogged=true]: minecraft:waxed_weathered_copper_grate[waterlogged=true] + minecraft:exposed_copper_grate[waterlogged=false]: minecraft:waxed_exposed_copper_grate[waterlogged=false] + minecraft:exposed_copper_grate[waterlogged=true]: minecraft:waxed_exposed_copper_grate[waterlogged=true] + minecraft:oxidized_copper_grate[waterlogged=false]: minecraft:waxed_oxidized_copper_grate[waterlogged=false] + minecraft:oxidized_copper_grate[waterlogged=true]: minecraft:waxed_oxidized_copper_grate[waterlogged=true] + + #### Pressure Plate #### + # Triggered pressure plates appear identical, even though they output different signal strengths. + minecraft:light_weighted_pressure_plate[power=2]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=3]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=4]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=5]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=6]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=7]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=8]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=9]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=10]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=11]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=12]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=13]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=14]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:light_weighted_pressure_plate[power=15]: minecraft:light_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=2]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=3]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=4]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=5]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=6]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=7]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=8]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=9]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=10]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=11]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=12]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=13]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=14]: minecraft:heavy_weighted_pressure_plate[power=1] + minecraft:heavy_weighted_pressure_plate[power=15]: minecraft:heavy_weighted_pressure_plate[power=1] + + #### Corals #### + # Coral blocks are ideal for creating water blocks or wall-mounted blocks. But you have to sacrifice its dry appearance. + # minecraft:dead_brain_coral[waterlogged=false]: minecraft:brain_coral[waterlogged=false] + # minecraft:dead_brain_coral[waterlogged=true]: minecraft:brain_coral[waterlogged=true] + # minecraft:dead_brain_coral_fan[waterlogged=false]: minecraft:brain_coral_fan[waterlogged=false] + # minecraft:dead_brain_coral_fan[waterlogged=true]: minecraft:brain_coral_fan[waterlogged=true] + # minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=east]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=east] + # minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=north]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=north] + # minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=south]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=south] + # minecraft:dead_brain_coral_wall_fan[waterlogged=false,facing=west]: minecraft:brain_coral_wall_fan[waterlogged=false,facing=west] + # minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=east]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=east] + # minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=north]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=north] + # minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=south]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=south] + # minecraft:dead_brain_coral_wall_fan[waterlogged=true,facing=west]: minecraft:brain_coral_wall_fan[waterlogged=true,facing=west] + # minecraft:dead_bubble_coral[waterlogged=false]: minecraft:bubble_coral[waterlogged=false] + # minecraft:dead_bubble_coral[waterlogged=true]: minecraft:bubble_coral[waterlogged=true] + # minecraft:dead_bubble_coral_fan[waterlogged=false]: minecraft:bubble_coral_fan[waterlogged=false] + # minecraft:dead_bubble_coral_fan[waterlogged=true]: minecraft:bubble_coral_fan[waterlogged=true] + # minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=east] + # minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=north] + # minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=south] + # minecraft:dead_bubble_coral_wall_fan[waterlogged=false,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=false,facing=west] + # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=east]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=east] + # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=north]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=north] + # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=south]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=south] + # minecraft:dead_bubble_coral_wall_fan[waterlogged=true,facing=west]: minecraft:bubble_coral_wall_fan[waterlogged=true,facing=west] + # minecraft:dead_fire_coral[waterlogged=false]: minecraft:fire_coral[waterlogged=false] + # minecraft:dead_fire_coral[waterlogged=true]: minecraft:fire_coral[waterlogged=true] + # minecraft:dead_fire_coral_fan[waterlogged=false]: minecraft:fire_coral_fan[waterlogged=false] + # minecraft:dead_fire_coral_fan[waterlogged=true]: minecraft:fire_coral_fan[waterlogged=true] + # minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=east] + # minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=north] + # minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=south] + # minecraft:dead_fire_coral_wall_fan[waterlogged=false,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=false,facing=west] + # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=east]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=east] + # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=north]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=north] + # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=south]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=south] + # minecraft:dead_fire_coral_wall_fan[waterlogged=true,facing=west]: minecraft:fire_coral_wall_fan[waterlogged=true,facing=west] + # minecraft:dead_horn_coral[waterlogged=false]: minecraft:horn_coral[waterlogged=false] + # minecraft:dead_horn_coral[waterlogged=true]: minecraft:horn_coral[waterlogged=true] + # minecraft:dead_horn_coral_fan[waterlogged=false]: minecraft:horn_coral_fan[waterlogged=false] + # minecraft:dead_horn_coral_fan[waterlogged=true]: minecraft:horn_coral_fan[waterlogged=true] + # minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=east] + # minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=north] + # minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=south] + # minecraft:dead_horn_coral_wall_fan[waterlogged=false,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=false,facing=west] + # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=east]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=east] + # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=north]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=north] + # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=south]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=south] + # minecraft:dead_horn_coral_wall_fan[waterlogged=true,facing=west]: minecraft:horn_coral_wall_fan[waterlogged=true,facing=west] + # minecraft:dead_tube_coral[waterlogged=false]: minecraft:tube_coral[waterlogged=false] + # minecraft:dead_tube_coral[waterlogged=true]: minecraft:tube_coral[waterlogged=true] + # minecraft:dead_tube_coral_fan[waterlogged=false]: minecraft:tube_coral_fan[waterlogged=false] + # minecraft:dead_tube_coral_fan[waterlogged=true]: minecraft:tube_coral_fan[waterlogged=true] + # minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=east]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=east] + # minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=north]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=north] + # minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=south]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=south] + # minecraft:dead_tube_coral_wall_fan[waterlogged=false,facing=west]: minecraft:tube_coral_wall_fan[waterlogged=false,facing=west] + # minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=east]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=east] + # minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=north]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=north] + # minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=south]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=south] + # minecraft:dead_tube_coral_wall_fan[waterlogged=true,facing=west]: minecraft:tube_coral_wall_fan[waterlogged=true,facing=west] + + #### Chorus Plant #### + # Chorus Plant does support transparent textures, but man... its hitbox is super weird. You're probably better off using leaves. + # minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=false,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=false]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=false,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=false,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=true,south=false,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=true,north=false,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=false,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=true,east=false,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] + # minecraft:chorus_plant[down=false,east=true,north=true,south=true,up=true,west=true]: minecraft:chorus_plant[down=true,east=true,north=true,south=true,up=true,west=true] \ No newline at end of file diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index f22dc1863..4e28bf879 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -264,7 +264,6 @@ warning.config.block.state.unavailable_vanilla: "Problem in Datei Problem in Datei gefunden - Der Block '' verwendet einen Vanilla-Block-State '', der den verfügbaren Slot-Bereich '0~' überschreitet." warning.config.block.state.conflict: "Problem in Datei gefunden - Der Block '' verwendet einen Vanilla-Block-State '', der bereits von '' belegt ist." warning.config.block.state.bind_failed: "Problem in Datei gefunden - Der Block '' konnte den echten Block-State für '' nicht binden, da der State bereits von '' belegt ist." -warning.config.block.state.invalid_real_id: "Problem in Datei gefunden - Der Block '' verwendet einen echten Block-State '', der den verfügbaren Slot-Bereich '0~' überschreitet. Erwäge, weitere echte States in 'additional-real-blocks.yml' hinzuzufügen, wenn die Slots aufgebraucht sind." warning.config.block.state.model.missing_path: "Problem in Datei gefunden - Beim Block '' fehlt die erforderliche 'path'-Option für 'model'." warning.config.block.state.model.invalid_path: "Problem in Datei gefunden - Der Block '' hat ein 'path'-Argument '', das ungültige Zeichen enthält. Bitte lies https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.block.state.model.conflict: "Problem in Datei gefunden - Der Block '' versucht, das Model '' an den Block-State '' zu binden, der bereits an das Model '' gebunden ist." diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 092ca02ce..8bfe8c7ad 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -255,6 +255,8 @@ warning.config.item.model.special.head.missing_kind: "Issue found in fil warning.config.item.updater.missing_type: "Issue found in file - The item '' is missing the required 'type' argument for item updater." warning.config.item.updater.invalid_type: "Issue found in file - The item '' is using an invalid 'type' argument '' for item updater." warning.config.item.updater.transmute.missing_material: "Issue found in file - The item '' is missing the required 'material' argument for 'transmute' item updater." +warning.config.block_state_mapping.invalid_state: "Issue found in file - The config '' is using an invalid block state ''." +warning.config.block_state_mapping.conflict: "Issue found in file - The config '' is unable to map block state to block state because the state has already been mapped to ." warning.config.block.duplicate: "Issue found in file - Duplicated block ''. Please check if there is the same configuration in other files." warning.config.block.missing_state: "Issue found in file - The block '' is missing the required 'state' argument." warning.config.block.state.property.missing_type: "Issue found in file - The block '' is missing the required 'type' argument for property ''." @@ -278,7 +280,7 @@ warning.config.block.state.unavailable_vanilla: "Issue found in file Issue found in file - The block '' is using a vanilla block state '' that exceeds the available slot range '0~'." warning.config.block.state.conflict: "Issue found in file - The block '' is using a vanilla block state '' that has been occupied by ''." warning.config.block.state.bind_failed: "Issue found in file - The block '' failed to bind real block state '' for '' as the state has been occupied by ''." -warning.config.block.state.invalid_real_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more real states in 'additional-real-blocks.yml' if the slots are used up." +warning.config.block.state.invalid_real_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more serverside blocks in 'config.yml' if the slots are used up." warning.config.block.state.model.missing_path: "Issue found in file - The block '' is missing the required 'path' option for 'model'." warning.config.block.state.model.invalid_path: "Issue found in file - The block '' has a 'path' argument '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.block.state.model.conflict: "Issue found in file - The block '' is trying to bind model '' to block state '' which has already been bound to model ''" diff --git a/common-files/src/main/resources/translations/es.yml b/common-files/src/main/resources/translations/es.yml index 77b0cc709..0429bbb86 100644 --- a/common-files/src/main/resources/translations/es.yml +++ b/common-files/src/main/resources/translations/es.yml @@ -187,7 +187,6 @@ warning.config.block.state.unavailable_vanilla: "Problema encontrado en warning.config.block.state.invalid_vanilla_id: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla '' que excede el rango de slots disponible '0~'." warning.config.block.state.conflict: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla '' que está ocupado por ''." warning.config.block.state.bind_failed: "Problema encontrado en el archivo - El bloque '' falló al vincular el estado de bloque real para '' porque está ocupado por el estado ''." -warning.config.block.state.invalid_real_id: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque real '' que excede el rango de slots disponible '0~'. Si los slots están usados, considera agregar más estados reales a 'additional-real-blocks.yml'." warning.config.block.state.model.missing_path: "Problema encontrado en el archivo - El bloque '' carece de la opción requerida 'path' para 'model'." warning.config.block.state.model.invalid_path: "Problema encontrado en el archivo - El bloque '' tiene un argumento 'path' '' que contiene caracteres prohibidos. Por favor lee https://minecraft.wiki/w/Resource_location#Legal_characters" warning.config.block.settings.unknown: "Problema encontrado en el archivo - El bloque '' está usando un tipo de configuración desconocido ''." diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml index 209c6cf28..dcb624e7a 100644 --- a/common-files/src/main/resources/translations/ru_ru.yml +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -237,7 +237,6 @@ warning.config.block.state.unavailable_vanilla: "Проблема най warning.config.block.state.invalid_vanilla_id: "Проблема найдена в файле - Блок '' использует состояние ванильного блока '', что превышает доступный диапазон слотов '0~'." warning.config.block.state.conflict: "Проблема найдена в файле - Блок '' использует состояние ванильного блока '' которое занято ''." warning.config.block.state.bind_failed: "Проблема найдена в файле - Блоку '' не удалось привязать реальное состояние блока для '', так как состояние занято ''." -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: "Проблема найдена в файле - Блок '' использует неизвестный тип настройки ''." diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index d1cff3a7c..e5b79c186 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -185,7 +185,6 @@ warning.config.block.state.unavailable_vanilla: " dosyasında sor warning.config.block.state.invalid_vanilla_id: " dosyasında sorun bulundu - '' bloğu, mevcut yuva aralığı '0~' aşan bir vanilya blok durumu '' kullanıyor." warning.config.block.state.conflict: " dosyasında sorun bulundu - '' bloğu, '' tarafından işgal edilmiş bir vanilya blok durumu '' kullanıyor." warning.config.block.state.bind_failed: " dosyasında sorun bulundu - '' bloğu, durum '' tarafından işgal edildiği için '' için gerçek blok durumu bağlamada başarısız oldu." -warning.config.block.state.invalid_real_id: " dosyasında sorun bulundu - '' bloğu, mevcut yuva aralığı '0~' aşan bir gerçek blok durumu '' kullanıyor. Yuvalar kullanılmışsa, 'additional-real-blocks.yml' dosyasına daha fazla gerçek durum eklemeyi düşünün." warning.config.block.state.model.missing_path: " dosyasında sorun bulundu - '' bloğu, 'model' için gerekli 'path' seçeneği eksik." warning.config.block.state.model.invalid_path: " dosyasında sorun bulundu - '' bloğunun, yasak karakterler içeren bir 'path' argümanı '' var. Lütfen https://minecraft.wiki/w/Resource_location#Legal_characters sayfasını okuyun." warning.config.block.settings.unknown: " dosyasında sorun bulundu - '' bloğu bilinmeyen bir ayar türü '' kullanıyor." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 8b6fc7227..56720fb27 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -272,7 +272,7 @@ warning.config.block.state.unavailable_vanilla: "在文件 发 warning.config.block.state.invalid_vanilla_id: "在文件 发现问题 - 方块 '' 使用的原版方块状态 '' 超出可用槽位范围 '0~'" warning.config.block.state.conflict: "在文件 发现问题 - 方块 '' 使用的原版方块状态 '' 已被 '' 占用" warning.config.block.state.bind_failed: "在文件 发现问题 - 方块 '' 无法为 '' 绑定真实方块状态 '' 因该状态已被 '' 占用" -warning.config.block.state.invalid_real_id: "在文件 发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~' 如果槽位已用尽 请在 additional-real-blocks.yml 中添加更多真实状态" +warning.config.block.state.invalid_real_id: "在文件 发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~' 如果槽位已用尽 请在 config.yml 中添加更多服务端侧方块" warning.config.block.state.model.missing_path: "在文件 发现问题 - 方块 '' 的 'model' 缺少必需的 'path' 选项" warning.config.block.state.model.invalid_path: "在文件 发现问题 - 方块 '' 的 'path' 参数 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" warning.config.block.state.model.conflict: "在文件 发现问题 - 方块 '' 正尝试将模型 '' 绑定到方块状态 '' 上, 但是此状态已绑定了另一个模型 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 458587234..aeeebaea8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -2,8 +2,8 @@ package net.momirealms.craftengine.core.block; import com.google.gson.JsonElement; import com.google.gson.JsonObject; -import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntArrayList; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigs; @@ -16,54 +16,81 @@ import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.*; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.util.GsonHelper; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.nio.file.Path; import java.util.*; -import java.util.function.Function; +import java.util.function.Predicate; public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager { protected final BlockParser blockParser; - // CraftEngine objects + protected final BlockStateMappingParser blockStateMappingParser; + // 根据id获取自定义方块 protected final Map byId = new HashMap<>(); - // Cached command suggestions + // 缓存的指令建议 protected final List cachedSuggestions = new ArrayList<>(); - // Cached Namespace + // 缓存的使用中的命名空间 protected final Set namespacesInUse = new HashSet<>(); - // for mod, real block id -> state models - protected final Map modBlockStates = new HashMap<>(); - // A temporary map that stores the model path of a certain vanilla block state + // 用于检测单个外观方块状态是否被绑定了不同模型 protected final Map tempVanillaBlockStateModels = new Int2ObjectOpenHashMap<>(); - // A temporary map used to detect whether the same block state corresponds to multiple models. - protected final Map tempRegistryIdConflictMap = new Int2ObjectOpenHashMap<>(); - // A temporary map that converts the custom block registered on the server to the vanilla block ID. - protected final Map tempBlockAppearanceConvertor = new Int2IntOpenHashMap(); - // Used to store override information of json files + // Map<方块类型, Map<方块状态NBT,模型>>,用于生成block state json protected final Map> blockStateOverrides = new HashMap<>(); - // a reverted mapper + // 用于生成mod使用的block state json + protected final Map modBlockStateOverrides = new HashMap<>(); + // 根据外观查找真实状态,用于debug指令 protected final Map> appearanceToRealState = new Int2ObjectOpenHashMap<>(); + // 声音映射表,和使用了哪些视觉方块有关 + protected final Map soundReplacements = new HashMap<>(512, 0.5f); + // 用于note_block:0这样格式的自动分配 + protected final Map> blockStateArranger = new HashMap<>(); + // 全方块状态映射文件,用于网络包映射 + protected final int[] blockStateMappings; + // 原版方块状态数量 + protected final int vanillaBlockStateCount; + // 注册的大宝贝 + protected final DelegatingBlock[] customBlocks; + protected final DelegatingBlockState[] customBlockStates; + protected final Object[] customBlockHolders; + // 自定义状态列表,会随着重载变化 + protected final ImmutableBlockState[] immutableBlockStates; + // 原版方块的属性缓存 + protected final BlockSettings[] vanillaBlockSettings; - // client side block tags - protected Map> clientBoundTags = Map.of(); - protected Map> previousClientBoundTags = Map.of(); - // Used to automatically arrange block states for strings such as minecraft:note_block:0 - protected Map> blockAppearanceArranger; - protected Map> realBlockArranger; - protected Map internalId2StateId; - protected Map registeredBlocks; - - protected AbstractBlockManager(CraftEngine plugin) { + protected AbstractBlockManager(CraftEngine plugin, int vanillaBlockStateCount, int customBlockCount) { super(plugin); + this.vanillaBlockStateCount = vanillaBlockStateCount; this.blockParser = new BlockParser(); + this.blockStateMappingParser = new BlockStateMappingParser(); + this.customBlocks = new DelegatingBlock[customBlockCount]; + this.customBlockHolders = new Object[customBlockCount]; + this.customBlockStates = new DelegatingBlockState[customBlockCount]; + this.vanillaBlockSettings = new BlockSettings[vanillaBlockStateCount]; + this.immutableBlockStates = new ImmutableBlockState[customBlockCount]; + this.blockStateMappings = new int[customBlockCount + vanillaBlockStateCount]; + Arrays.fill(this.blockStateMappings, -1); + } + + @NotNull + @Override + public ImmutableBlockState getImmutableBlockStateUnsafe(int stateId) { + return this.immutableBlockStates[stateId - this.vanillaBlockStateCount]; + } + + @Nullable + @Override + public ImmutableBlockState getImmutableBlockState(int stateId) { + if (!isVanillaBlockState(stateId)) { + return this.immutableBlockStates[stateId - this.vanillaBlockStateCount]; + } + return null; } @Override @@ -71,12 +98,15 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem super.clearModelsToGenerate(); this.clearCache(); this.cachedSuggestions.clear(); + this.namespacesInUse.clear(); this.blockStateOverrides.clear(); - this.modBlockStates.clear(); + this.modBlockStateOverrides.clear(); this.byId.clear(); - this.previousClientBoundTags = this.clientBoundTags; - this.clientBoundTags = new HashMap<>(); + this.soundReplacements.clear(); + this.blockStateArranger.clear(); this.appearanceToRealState.clear(); + Arrays.fill(this.blockStateMappings, -1); + Arrays.fill(this.immutableBlockStates, EmptyBlock.STATE); } @Override @@ -97,23 +127,39 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } protected void addBlockInternal(Key id, CustomBlock customBlock) { - this.byId.put(id, customBlock); - // generate mod assets - if (Config.generateModAssets()) { - for (ImmutableBlockState state : customBlock.variantProvider().states()) { - this.modBlockStates.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(state.vanillaBlockState().registryId())); + ExceptionCollector exceptionCollector = new ExceptionCollector<>(); + // 绑定外观状态等 + for (ImmutableBlockState state : customBlock.variantProvider().states()) { + int internalId = state.customBlockState().registryId(); + int appearanceId = state.vanillaBlockState().registryId(); + int index = internalId - this.vanillaBlockStateCount; + ImmutableBlockState previous = this.immutableBlockStates[index]; + // todo 应当提前判断位置 + if (previous != null && !previous.isEmpty()) { + exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.bind_failed", + state.toString(), previous.toString(), getBlockOwnerId(previous.customBlockState()).toString())); + continue; + } + this.immutableBlockStates[index] = state; + this.blockStateMappings[internalId] = appearanceId; + this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId); + // generate mod assets + if (Config.generateModAssets()) { + this.modBlockStateOverrides.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(appearanceId)); } } + this.byId.put(id, customBlock); + exceptionCollector.throwIfPresent(); } @Override - public ConfigParser parser() { - return this.blockParser; + public ConfigParser[] parsers() { + return new ConfigParser[]{this.blockParser, this.blockStateMappingParser}; } @Override public Map modBlockStates() { - return Collections.unmodifiableMap(this.modBlockStates); + return Collections.unmodifiableMap(this.modBlockStateOverrides); } @Override @@ -126,13 +172,21 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Collections.unmodifiableCollection(this.cachedSuggestions); } + @Nullable + public Key replaceSoundIfExist(Key id) { + return this.soundReplacements.get(id); + } + + @Override + public Map soundReplacements() { + return Collections.unmodifiableMap(this.soundReplacements); + } + public Set namespacesInUse() { return Collections.unmodifiableSet(this.namespacesInUse); } protected void clearCache() { - this.tempRegistryIdConflictMap.clear(); - this.tempBlockAppearanceConvertor.clear(); this.tempVanillaBlockStateModels.clear(); } @@ -161,15 +215,55 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected abstract boolean isVanillaBlock(Key id); - protected abstract int getBlockRegistryId(Key id); - - protected abstract String stateRegistryIdToStateSNBT(int id); - protected abstract Key getBlockOwnerId(int id); protected abstract CustomBlock.Builder platformBuilder(Key id); - public class BlockParser implements ConfigParser { + protected abstract void setVanillaBlockTags(Key id, List tags); + + public abstract int vanillaBlockStateCount(); + + public class BlockStateMappingParser implements SectionConfigParser { + public static final String[] CONFIG_SECTION_NAME = new String[]{"block-state-mappings", "block-state-mapping"}; + + @Override + public String[] sectionId() { + return CONFIG_SECTION_NAME; + } + + @Override + public int loadingSequence() { + return LoadingSequence.BLOCK_STATE_MAPPING; + } + + @Override + public void parseSection(Pack pack, Path path, Map section) throws LocalizedException { + for (Map.Entry entry : section.entrySet()) { + String before = entry.getKey(); + String after = entry.getValue().toString(); + // 先解析为唯一的wrapper + BlockStateWrapper beforeState = createVanillaBlockState(before); + BlockStateWrapper afterState = createVanillaBlockState(before); + if (beforeState == null) { + TranslationManager.instance().log("warning.config.block_state_mapping.invalid_state", path.toString(), before); + return; + } + if (afterState == null) { + TranslationManager.instance().log("warning.config.block_state_mapping.invalid_state", path.toString(), after); + return; + } + int previous = AbstractBlockManager.this.blockStateMappings[beforeState.registryId()]; + if (previous != -1 && previous != afterState.registryId()) { + TranslationManager.instance().log("warning.config.block_state_mapping.conflict", path.toString(), beforeState.toString(), afterState.toString(), BlockRegistryMirror.byId(previous).toString()); + return; + } + AbstractBlockManager.this.blockStateMappings[beforeState.registryId()] = afterState.registryId(); + AbstractBlockManager.this.blockStateArranger.computeIfAbsent(getBlockOwnerId(beforeState), k -> new ArrayList<>()).add(afterState); + } + } + } + + public class BlockParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; @Override @@ -201,7 +295,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem Object clientBoundTags = settings.get("client-bound-tags"); if (clientBoundTags instanceof List list) { List clientSideTags = MiscUtils.getAsStringList(list).stream().filter(ResourceLocation::isValid).toList(); - AbstractBlockManager.this.clientBoundTags.put(getBlockRegistryId(id), clientSideTags); + AbstractBlockManager.this.setVanillaBlockTags(id, clientSideTags); } } } @@ -219,19 +313,16 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem boolean singleState = !stateSection.containsKey("properties"); // 单方块状态 if (singleState) { - int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow( - stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); + int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); // 获取原版外观的注册表id - int appearanceId = pluginFormattedBlockStateToRegistryId(ResourceConfigUtils.requireNonEmptyStringOrThrow( - stateSection.get("state"), "warning.config.block.state.missing_state")); + BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(stateSection.get("state"), "warning.config.block.state.missing_state")); Optional[]> blockEntityRenderer = parseBlockEntityRender(stateSection.get("entity-renderer")); - // 为原版外观赋予外观模型并检查模型冲突 - this.arrangeModelForStateAndVerify(appearanceId, ResourceConfigUtils.get(stateSection, "model", "models")); + this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(stateSection, "model", "models")); // 设置参数 properties = Map.of(); - appearances = Map.of("", new BlockStateAppearance(appearanceId, blockEntityRenderer)); - variants = Map.of("", new BlockStateVariant("", settings, getInternalBlockId(internalId, appearanceId))); + appearances = Map.of("", new BlockStateAppearance(appearanceState, blockEntityRenderer)); + variants = Map.of("", new BlockStateVariant("", settings, getInternalBlockState(internalId))); } // 多方块状态 else { @@ -239,10 +330,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem appearances = parseBlockAppearances(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances")); variants = parseBlockVariants( ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), "variants"), - it -> { - BlockStateAppearance blockStateAppearance = appearances.get(it); - return blockStateAppearance == null ? -1 : blockStateAppearance.stateRegistryId(); - }, settings + appearances::containsKey, settings ); } @@ -258,39 +346,35 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } private Map parseBlockVariants(Map variantsSection, - Function appearanceValidator, + Predicate appearanceValidator, BlockSettings parentSettings) { Map variants = new HashMap<>(); for (Map.Entry entry : variantsSection.entrySet()) { Map variantSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); String variantNBT = entry.getKey(); String appearance = ResourceConfigUtils.requireNonEmptyStringOrThrow(variantSection.get("appearance"), "warning.config.block.state.variant.missing_appearance"); - int appearanceId = appearanceValidator.apply(appearance); - if (appearanceId == -1) { + if (!appearanceValidator.test(appearance)) { throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearance); } - int internalId = getInternalBlockId(ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id"), appearanceId); + BlockStateWrapper internalBlockState = getInternalBlockState(ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id")); Map anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings"); - variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? parentSettings : BlockSettings.ofFullCopy(parentSettings, anotherSetting), internalId)); + variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? parentSettings : BlockSettings.ofFullCopy(parentSettings, anotherSetting), internalBlockState)); } return variants; } - private int getInternalBlockId(int internalId, int appearanceId) { - Key baseBlock = getBlockOwnerId(appearanceId); - Key internalBlockId = Key.of(Key.DEFAULT_NAMESPACE, baseBlock.value() + "_" + internalId); - int internalBlockRegistryId = Optional.ofNullable(AbstractBlockManager.this.internalId2StateId.get(internalBlockId)).orElse(-1); - if (internalBlockRegistryId == -1) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", internalBlockId.toString(), String.valueOf(availableAppearances(baseBlock) - 1)); + private BlockStateWrapper getInternalBlockState(int internalId) { + if (internalId >= Config.serverSideBlocks()) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", BlockManager.createCustomBlockKey(internalId).asString(), String.valueOf(Config.serverSideBlocks() - 1)); } - return internalBlockRegistryId; + return BlockRegistryMirror.byId(internalId + vanillaBlockStateCount()); } private Map parseBlockAppearances(Map appearancesSection) { Map appearances = new HashMap<>(); for (Map.Entry entry : appearancesSection.entrySet()) { Map appearanceSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); - int appearanceId = pluginFormattedBlockStateToRegistryId(ResourceConfigUtils.requireNonEmptyStringOrThrow( + BlockStateWrapper appearanceId = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow( appearanceSection.get("state"), "warning.config.block.state.missing_state")); this.arrangeModelForStateAndVerify(appearanceId, ResourceConfigUtils.get(appearanceSection, "model", "models")); appearances.put(entry.getKey(), new BlockStateAppearance(appearanceId, parseBlockEntityRender(appearanceSection.get("entity-renderer")))); @@ -316,7 +400,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return properties; } - private void arrangeModelForStateAndVerify(int registryId, Object modelOrModels) { + private void arrangeModelForStateAndVerify(BlockStateWrapper blockStateWrapper, Object modelOrModels) { // 如果没有配置models if (modelOrModels == null) { return; @@ -334,13 +418,13 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } // 拆分方块id与属性 - String blockState = stateRegistryIdToStateSNBT(registryId); + String blockState = blockStateWrapper.toString(); Key blockId = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}'))); String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']')); // 结合variants JsonElement combinedVariant = GsonHelper.combine(variants); Map overrideMap = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()); - AbstractBlockManager.this.tempVanillaBlockStateModels.put(registryId, combinedVariant); + AbstractBlockManager.this.tempVanillaBlockStateModels.put(blockStateWrapper.registryId(), combinedVariant); JsonElement previous = overrideMap.get(propertyNBT); if (previous != null && !previous.equals(combinedVariant)) { throw new LocalizedResourceConfigException("warning.config.block.state.model.conflict", GsonHelper.get().toJson(combinedVariant), blockState, GsonHelper.get().toJson(previous)); @@ -370,7 +454,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } // 从方块外观的state里获取其原版方块的state id - private int pluginFormattedBlockStateToRegistryId(String blockState) { + private BlockStateWrapper parsePluginFormattedBlockState(String blockState) { // 五种合理情况 // minecraft:note_block:10 // note_block:10 @@ -381,7 +465,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem if (split.length >= 4) { throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); } - int registryId; + BlockStateWrapper wrapper; String stateOrId = split[split.length - 1]; boolean isId = false; int arrangerIndex = 0; @@ -401,14 +485,14 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 获取原版方块的id Key block = split.length == 2 ? Key.of(split[0]) : Key.of(split[0], split[1]); try { - List arranger = blockAppearanceArranger.get(block); + List arranger =blockStateArranger.get(block); if (arranger == null) { throw new LocalizedResourceConfigException("warning.config.block.state.unavailable_vanilla", blockState); } if (arrangerIndex >= arranger.size()) { throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla_id", blockState, String.valueOf(arranger.size() - 1)); } - registryId = arranger.get(arrangerIndex); + wrapper = arranger.get(arrangerIndex); } catch (NumberFormatException e) { throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", e, blockState); } @@ -418,9 +502,21 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem if (packedBlockState == null) { throw new LocalizedResourceConfigException("warning.config.block.state.invalid_vanilla", blockState); } - registryId = packedBlockState.registryId(); + wrapper = packedBlockState; } - return registryId; + return wrapper; } } + + public boolean isVanillaBlockState(int id) { + return id < this.vanillaBlockStateCount && id >= 0; + } + + public BlockParser blockParser() { + return blockParser; + } + + public BlockStateMappingParser blockStateMappingParser() { + return blockStateMappingParser; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java index 92593999c..d62c103d8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java @@ -61,6 +61,7 @@ public abstract class AbstractCustomBlock implements CustomBlock { this.placementFunction = composite(placements); EntityBlockBehavior entityBlockBehavior = this.behavior.getEntityBehavior(); boolean isEntityBlock = entityBlockBehavior != null; + for (Map.Entry entry : variantMapper.entrySet()) { String nbtString = entry.getKey(); CompoundTag tag = BlockNbtParser.deserialize(this, nbtString); @@ -72,20 +73,12 @@ public abstract class AbstractCustomBlock implements CustomBlock { throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString); } BlockStateVariant blockStateVariant = entry.getValue(); - - BlockStateAppearance blockStateAppearance = appearances.getOrDefault(blockStateVariant.appearance(), BlockStateAppearance.INVALID); - int stateId; - // This should never happen - if (blockStateAppearance.isInvalid()) { - stateId = appearances.values().iterator().next().stateRegistryId(); - } else { - stateId = blockStateAppearance.stateRegistryId(); - } + BlockStateAppearance blockStateAppearance = appearances.get(blockStateVariant.appearance()); // Late init states ImmutableBlockState state = possibleStates.getFirst(); state.setSettings(blockStateVariant.settings()); - state.setVanillaBlockState(BlockRegistryMirror.stateByRegistryId(stateId)); - state.setCustomBlockState(BlockRegistryMirror.stateByRegistryId(blockStateVariant.internalRegistryId())); + state.setVanillaBlockState(blockStateAppearance.blockState()); + state.setCustomBlockState(blockStateVariant.blockState()); blockStateAppearance.blockEntityRenderer().ifPresent(state::setConstantRenderers); } @@ -99,7 +92,6 @@ public abstract class AbstractCustomBlock implements CustomBlock { state.setBlockEntityType(entityBlockBehavior.blockEntityType()); } } - this.applyPlatformSettings(); } protected BlockBehavior setupBehavior(List> behaviorConfig) { @@ -124,8 +116,6 @@ public abstract class AbstractCustomBlock implements CustomBlock { }; } - protected abstract void applyPlatformSettings(); - @Override public @Nullable LootTable lootTable() { return this.lootTable; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java index 785d13b17..1246a2bae 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockManager.java @@ -16,7 +16,7 @@ import java.util.Optional; public interface BlockManager extends Manageable, ModelGenerator { - ConfigParser parser(); + ConfigParser[] parsers(); Collection modelsToGenerate(); @@ -35,9 +35,7 @@ public interface BlockManager extends Manageable, ModelGenerator { Collection cachedSuggestions(); - Map soundMapper(); - - int availableAppearances(Key blockType); + Map soundReplacements(); Key getBlockOwnerId(BlockStateWrapper state); @@ -49,4 +47,11 @@ public interface BlockManager extends Manageable, ModelGenerator { @Nullable BlockStateWrapper createBlockState(String blockState); + + @Nullable + BlockStateWrapper createVanillaBlockState(String blockState); + + static Key createCustomBlockKey(int id) { + return Key.of("craftengine", "custom_" + id); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java index acd70d21e..ccc19d42e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockRegistryMirror.java @@ -5,14 +5,14 @@ public final class BlockRegistryMirror { private static BlockStateWrapper stoneState; public static void init(BlockStateWrapper[] states, BlockStateWrapper state) { - if (blockStates != null) throw new IllegalStateException("block states are already set"); + if (blockStates != null) throw new IllegalStateException("block states have already been set"); blockStates = states; stoneState = state; } - public static BlockStateWrapper stateByRegistryId(int vanillaId) { - if (vanillaId < 0) return stoneState; - return blockStates[vanillaId]; + public static BlockStateWrapper byId(int stateId) { + if (stateId < 0) return stoneState; + return blockStates[stateId]; } public static int size() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java index 88d517857..d393d4b9d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java @@ -15,25 +15,20 @@ public final class BlockSounds { Land 0.3 1 Destroy 1 1 */ - public static final SoundData EMPTY_SOUND = new SoundData(Key.of("minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1); - public static final BlockSounds EMPTY = new BlockSounds(EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND, EMPTY_SOUND); + public static final BlockSounds EMPTY = new BlockSounds(SoundData.EMPTY, SoundData.EMPTY, SoundData.EMPTY, SoundData.EMPTY, SoundData.EMPTY); private final SoundData breakSound; private final SoundData stepSound; private final SoundData placeSound; private final SoundData hitSound; private final SoundData fallSound; - private final SoundData landSound; - private final SoundData destroySound; - public BlockSounds(SoundData breakSound, SoundData stepSound, SoundData placeSound, SoundData hitSound, SoundData fallSound, SoundData landSound, SoundData destroySound) { + public BlockSounds(SoundData breakSound, SoundData stepSound, SoundData placeSound, SoundData hitSound, SoundData fallSound) { this.breakSound = breakSound; this.stepSound = stepSound; this.placeSound = placeSound; this.hitSound = hitSound; this.fallSound = fallSound; - this.landSound = landSound; - this.destroySound = destroySound; } public static BlockSounds fromMap(Map map) { @@ -43,16 +38,10 @@ public final class BlockSounds { SoundData.create(map.getOrDefault("step", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_15, SoundData.SoundValue.FIXED_1), SoundData.create(map.getOrDefault("place", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_0_8), SoundData.create(map.getOrDefault("hit", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.FIXED_0_5), - SoundData.create(map.getOrDefault("fall", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.FIXED_0_75), - SoundData.create(map.getOrDefault("land", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_3, SoundData.SoundValue.FIXED_1), - SoundData.create(map.getOrDefault("destroy", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1) + SoundData.create(map.getOrDefault("fall", "minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_0_5, SoundData.SoundValue.FIXED_0_75) ); } - public SoundData destroySound() { - return destroySound; - } - public SoundData breakSound() { return breakSound; } @@ -69,10 +58,6 @@ public final class BlockSounds { return hitSound; } - public SoundData landSound() { - return landSound; - } - public SoundData fallSound() { return fallSound; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateAppearance.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateAppearance.java index 0e2c7acc6..75e39df37 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateAppearance.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateAppearance.java @@ -5,10 +5,5 @@ import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityEl import java.util.Optional; -public record BlockStateAppearance(int stateRegistryId, Optional[]> blockEntityRenderer) { - public static final BlockStateAppearance INVALID = new BlockStateAppearance(-1, Optional.empty()); - - public boolean isInvalid() { - return this.stateRegistryId < 0; - } +public record BlockStateAppearance(BlockStateWrapper blockState, Optional[]> blockEntityRenderer) { } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java index cfe81345b..8a27403c8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java @@ -3,12 +3,12 @@ package net.momirealms.craftengine.core.block; public class BlockStateVariant { private final String appearance; private final BlockSettings settings; - private final int internalId; + private final BlockStateWrapper blockState; - public BlockStateVariant(String appearance, BlockSettings settings, int internalId) { + public BlockStateVariant(String appearance, BlockSettings settings, BlockStateWrapper blockState) { this.appearance = appearance; this.settings = settings; - this.internalId = internalId; + this.blockState = blockState; } public String appearance() { @@ -19,7 +19,7 @@ public class BlockStateVariant { return settings; } - public int internalRegistryId() { - return internalId; + public BlockStateWrapper blockState() { + return blockState; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java index fb880292e..846900088 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java @@ -1,8 +1,12 @@ package net.momirealms.craftengine.core.block; +import net.momirealms.craftengine.core.util.Key; + public interface BlockStateWrapper { Object literalObject(); int registryId(); + + Key ownerId(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/DelegatingBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/DelegatingBlock.java index ee4b7687f..e3bb1ae92 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/DelegatingBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/DelegatingBlock.java @@ -32,9 +32,11 @@ public interface DelegatingBlock { */ ObjectHolder behaviorDelegate(); + // 其实是错误的做法 @Deprecated boolean isNoteBlock(); + // 其实是错误的做法 @Deprecated boolean isTripwire(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java index 6570e95e8..a6aa4e0f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java @@ -15,8 +15,4 @@ public final class EmptyBlock extends AbstractCustomBlock { INSTANCE = this; STATE = defaultState(); } - - @Override - protected void applyPlatformSettings() { - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java index a68e0c461..3c16dcae3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java @@ -16,10 +16,6 @@ public final class InactiveCustomBlock extends AbstractCustomBlock { super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), List.of(), null); } - @Override - protected void applyPlatformSettings() { - } - @Override public ImmutableBlockState getBlockState(CompoundTag nbt) { return this.cachedData.computeIfAbsent(nbt, k -> { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/PushReaction.java b/core/src/main/java/net/momirealms/craftengine/core/block/PushReaction.java index db1d653be..5a7f65756 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/PushReaction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/PushReaction.java @@ -5,5 +5,7 @@ public enum PushReaction { DESTROY, BLOCK, IGNORE, - PUSH_ONLY + PUSH_ONLY; + + public static final PushReaction[] VALUES = values(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java index 233ad526b..fc3370fac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.block.properties; -import com.google.common.base.MoreObjects; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; 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 2e5b56471..3794e85f2 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 @@ -6,7 +6,7 @@ import net.momirealms.craftengine.core.loot.LootTable; 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.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; @@ -31,7 +31,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { } @Override - public ConfigParser parser() { + public IdSectionConfigParser parser() { return this.furnitureParser; } @@ -74,7 +74,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { protected abstract CustomFurniture.Builder furnitureBuilder(); - public class FurnitureParser implements ConfigParser { + public class FurnitureParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index cc5c6cdfb..11ef5e872 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -371,7 +372,7 @@ public abstract class AbstractFontManager implements FontManager { return this.fonts.computeIfAbsent(key, Font::new); } - public class EmojiParser implements ConfigParser { + public class EmojiParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"emoji", "emojis"}; @Override @@ -438,7 +439,7 @@ public abstract class AbstractFontManager implements FontManager { } } - public class ImageParser implements ConfigParser { + public class ImageParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"images", "image"}; @Override 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 61a06df52..75b4e4038 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 @@ -22,6 +22,7 @@ import net.momirealms.craftengine.core.pack.model.select.TrimMaterialSelectPrope 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.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; @@ -267,7 +268,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected abstract void registerArmorTrimPattern(Collection equipments); - public class EquipmentParser implements ConfigParser { + public class EquipmentParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"equipments", "equipment"}; @Override @@ -310,7 +311,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } - public class ItemParser implements ConfigParser { + public class ItemParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; private boolean isModernFormatRequired() { 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 670407315..c9db7e549 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 @@ -6,6 +6,7 @@ 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.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.UniqueKey; @@ -120,7 +121,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { return true; } - public class RecipeParser implements ConfigParser { + public class RecipeParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"}; @Override 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 2777d7c88..eab304ce6 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 @@ -27,9 +27,7 @@ import net.momirealms.craftengine.core.pack.obfuscation.ObfA; 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; -import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; +import net.momirealms.craftengine.core.plugin.config.*; import net.momirealms.craftengine.core.plugin.locale.I18NData; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -374,6 +372,7 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/internal/configuration/fix_client_visual.yml"); plugin.saveResource("resources/internal/configuration/offset_chars.yml"); plugin.saveResource("resources/internal/configuration/gui.yml"); + plugin.saveResource("resources/internal/configuration/mappings.yml"); plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/offset/space_split.png"); plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/item_browser.png"); plugin.saveResource("resources/internal/resourcepack/assets/minecraft/textures/font/gui/custom/category.png"); @@ -609,6 +608,7 @@ public abstract class AbstractPackManager implements PackManager { return cachedConfigs; } + // todo 本地化日志 private void loadResourceConfigs(Predicate predicate) { long o1 = System.nanoTime(); TreeMap> cachedConfigs = this.updateCachedConfigFiles(); @@ -619,34 +619,62 @@ public abstract class AbstractPackManager implements PackManager { 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(); - Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); - try { - if (parser.supportsParsingObject()) { - // do not apply templates - parser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue()); - } else { - if (configEntry.getValue() instanceof Map configSection0) { - Map config = castToMap(configSection0, false); - if ((boolean) config.getOrDefault("debug", false)) { - this.plugin.logger().info(GsonHelper.get().toJson(this.plugin.templateManager().applyTemplates(id, config))); - } - if ((boolean) config.getOrDefault("enable", true)) { - parser.parseSection(cached.pack(), cached.filePath(), id, MiscUtils.castToMap(this.plugin.templateManager().applyTemplates(id, config), false)); - } - } else { - TranslationManager.instance().log("warning.config.structure.not_section", cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); - } + switch (parser) { + case SectionConfigParser configParser -> { + for (CachedConfigSection cached : entry.getValue()) { + try { + configParser.parseSection(cached.pack(), cached.filePath(), cached.config()); + } catch (LocalizedException e) { + printWarningRecursively(e, cached.filePath(), cached.prefix()); + } catch (Exception e) { + this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "'. Please find the cause according to the stacktrace or seek developer help. Additional info: " + GsonHelper.get().toJson(cached.config()), e); } - } catch (LocalizedException e) { - printWarningRecursively(e, cached.filePath(), cached.prefix() + "." + key); - } 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); } } + case IdObjectConfigParser configParser -> { + for (CachedConfigSection cached : entry.getValue()) { + for (Map.Entry configEntry : cached.config().entrySet()) { + String key = configEntry.getKey(); + Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); + try { + configParser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue()); + } catch (LocalizedException e) { + printWarningRecursively(e, cached.filePath(), cached.prefix() + "." + key); + } 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); + } + } + } + } + case IdSectionConfigParser configParser -> { + for (CachedConfigSection cached : entry.getValue()) { + for (Map.Entry configEntry : cached.config().entrySet()) { + String key = configEntry.getKey(); + Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); + try { + if (configEntry.getValue() instanceof Map configSection0) { + Map config = castToMap(configSection0, false); + if ((boolean) config.getOrDefault("debug", false)) { + this.plugin.logger().info(GsonHelper.get().toJson(this.plugin.templateManager().applyTemplates(id, config))); + } + if ((boolean) config.getOrDefault("enable", true)) { + configParser.parseSection(cached.pack(), cached.filePath(), id, MiscUtils.castToMap(this.plugin.templateManager().applyTemplates(id, config), false)); + } + } else { + TranslationManager.instance().log("warning.config.structure.not_section", cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); + } + } catch (LocalizedException e) { + printWarningRecursively(e, cached.filePath(), cached.prefix() + "." + key); + } 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); + } + } + } + } + default -> { + } } + 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"); @@ -1722,7 +1750,7 @@ public abstract class AbstractPackManager implements PackManager { soundJson = new JsonObject(); } - for (Map.Entry mapper : plugin.blockManager().soundMapper().entrySet()) { + for (Map.Entry mapper : plugin.blockManager().soundReplacements().entrySet()) { Key originalKey = mapper.getKey(); JsonObject empty = new JsonObject(); empty.add("sounds", new JsonArray()); 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 82604386c..1868cd5fe 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 @@ -4,6 +4,7 @@ public final class LoadingSequence { private LoadingSequence() {} public static final int TEMPLATE = 0; + public static final int BLOCK_STATE_MAPPING = 5; public static final int GLOBAL_VAR = 10; public static final int LANG = 20; public static final int TRANSLATION = 30; 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 25bb1acf6..31327c6c2 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 @@ -92,6 +92,8 @@ public abstract class CraftEngine implements Plugin { protected CraftEngine(Consumer reloadEventDispatcher) { instance = this; this.reloadEventDispatcher = reloadEventDispatcher; + ((Logger) LogManager.getRootLogger()).addFilter(new LogFilter()); + ((Logger) LogManager.getRootLogger()).addFilter(new DisconnectLogFilter()); } public static CraftEngine instance() { @@ -105,9 +107,6 @@ public abstract class CraftEngine implements Plugin { RecipeDisplayTypes.init(); SlotDisplayTypes.init(); LegacyRecipeTypes.init(); - ((Logger) LogManager.getRootLogger()).addFilter(new LogFilter()); - ((Logger) LogManager.getRootLogger()).addFilter(new DisconnectLogFilter()); - this.config.load(); } public record ReloadResult(boolean success, long asyncTime, long syncTime) { @@ -281,7 +280,7 @@ public abstract class CraftEngine implements Plugin { // register furniture parser this.packManager.registerConfigSectionParser(this.furnitureManager.parser()); // register block parser - this.packManager.registerConfigSectionParser(this.blockManager.parser()); + this.packManager.registerConfigSectionParsers(this.blockManager.parsers()); // register recipe parser this.packManager.registerConfigSectionParser(this.recipeManager.parser()); // register category parser 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 65681858e..c2da59fa2 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 @@ -44,6 +44,7 @@ public class Config { protected boolean checkUpdate; protected boolean metrics; protected boolean filterConfigurationPhaseDisconnect; + protected Locale forcedLocale; protected boolean debug$common; protected boolean debug$packet; @@ -123,7 +124,7 @@ public class Config { protected int block$predict_breaking_interval; protected double block$extended_interaction_range; protected boolean block$chunk_relighter; - protected int block$serverside_blocks; + protected int block$serverside_blocks = -1; protected boolean recipe$enable; protected boolean recipe$disable_vanilla_recipes$all; @@ -177,7 +178,7 @@ public class Config { instance = this; } - public void load() { + public boolean updateConfigCache() { // 文件不存在,则保存 if (!Files.exists(this.configFilePath)) { this.plugin.saveResource("config.yml"); @@ -195,13 +196,20 @@ public class Config { this.updateConfigVersion(configFileBytes); } } - // 加载配置文件 - this.loadSettings(); this.lastModified = lastModified; this.size = size; + return true; } } catch (IOException e) { - this.plugin.logger().severe("Failed to load config.yml", e); + this.plugin.logger().severe("Failed to update config.yml", e); + } + return false; + } + + public void load() { + boolean isUpdated = updateConfigCache(); + if (isUpdated) { + loadFullSettings(); } } @@ -240,9 +248,14 @@ public class Config { } } - private void loadSettings() { + public void loadForcedLocale() { YamlDocument config = settings(); - plugin.translationManager().forcedLocale(TranslationManager.parseLocale(config.getString("forced-locale", ""))); + forcedLocale = TranslationManager.parseLocale(config.getString("forced-locale", "")); + } + + public void loadFullSettings() { + YamlDocument config = settings(); + forcedLocale = TranslationManager.parseLocale(config.getString("forced-locale", "")); // basics metrics = config.getBoolean("metrics", false); @@ -379,7 +392,7 @@ public class Config { 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$client_bound_model = config.getBoolean("item.client-bound-model", true) && VersionHelper.PREMIUM; item$non_italic_tag = config.getBoolean("item.non-italic-tag", false); item$update_triggers$attack = config.getBoolean("item.update-triggers.attack", false); item$update_triggers$click_in_inventory = config.getBoolean("item.update-triggers.click-in-inventory", false); @@ -394,7 +407,10 @@ public class Config { block$predict_breaking_interval = Math.max(config.getInt("block.predict-breaking.interval", 10), 1); block$extended_interaction_range = Math.max(config.getDouble("block.predict-breaking.extended-interaction-range", 0.5), 0.0); block$chunk_relighter = config.getBoolean("block.chunk-relighter", true); - block$serverside_blocks = config.getInt("block.serverside-blocks", 2000); + if (firstTime) { + block$serverside_blocks = config.getInt("block.serverside-blocks", 2000); + if (block$serverside_blocks < 0) block$serverside_blocks = 0; + } // recipe recipe$enable = config.getBoolean("recipe.enable", true); @@ -445,6 +461,10 @@ public class Config { return MinecraftVersion.parse(version); } + public static Locale forcedLocale() { + return instance.forcedLocale; + } + public static String configVersion() { return instance.configVersion; } @@ -465,6 +485,10 @@ public class Config { return false; } + public static boolean debugBlock() { + return false; + } + public static boolean debugFurniture() { return instance.debug$furniture; } 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 901fbe8a9..48ba108f9 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 @@ -1,30 +1,13 @@ package net.momirealms.craftengine.core.plugin.config; -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.plugin.locale.LocalizedException; -import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; -import java.nio.file.Path; -import java.util.Map; - public interface ConfigParser extends Comparable { String[] sectionId(); - default void parseSection(Pack pack, Path path, Key id, Map section) throws LocalizedException { - this.parseObject(pack, path, id, section); - } - - default void parseObject(Pack pack, Path path, Key id, Object object) throws LocalizedException { - } - int loadingSequence(); - default boolean supportsParsingObject() { - return false; - } - @Override default int compareTo(@NotNull ConfigParser another) { return Integer.compare(loadingSequence(), another.loadingSequence()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java new file mode 100644 index 000000000..2b2eb5125 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.plugin.config; + +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.Key; + +import java.nio.file.Path; + +public interface IdObjectConfigParser extends ConfigParser { + + default void parseObject(Pack pack, Path path, Key id, Object object) throws LocalizedException { + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java new file mode 100644 index 000000000..b137ebfe6 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java @@ -0,0 +1,14 @@ +package net.momirealms.craftengine.core.plugin.config; + +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.Key; + +import java.nio.file.Path; +import java.util.Map; + +public interface IdSectionConfigParser extends ConfigParser { + + default void parseSection(Pack pack, Path path, Key id, Map section) throws LocalizedException { + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/SectionConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/SectionConfigParser.java new file mode 100644 index 000000000..871d1674f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/SectionConfigParser.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.core.plugin.config; + +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.locale.LocalizedException; + +import java.nio.file.Path; +import java.util.Map; + +public interface SectionConfigParser extends ConfigParser { + + default void parseSection(Pack pack, Path path, Map section) throws LocalizedException { + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java index 398af24f7..9d1a505aa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.plugin.config.template; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdObjectConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -36,7 +37,7 @@ public class TemplateManagerImpl implements TemplateManager { return this.templateParser; } - public class TemplateParser implements ConfigParser { + public class TemplateParser implements IdObjectConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"templates", "template"}; @Override @@ -49,11 +50,6 @@ public class TemplateManagerImpl implements TemplateManager { return LoadingSequence.TEMPLATE; } - @Override - public boolean supportsParsingObject() { - return true; - } - @Override public void parseObject(Pack pack, Path path, Key id, Object obj) { if (templates.containsKey(id)) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java index bb2ab886d..d858deed2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdObjectConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import org.jetbrains.annotations.Nullable; @@ -34,7 +35,7 @@ public class GlobalVariableManager implements Manageable { return this.parser; } - public class GlobalVariableParser implements ConfigParser { + public class GlobalVariableParser implements IdObjectConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"global-variables", "global-variable"}; @Override @@ -47,11 +48,6 @@ public class GlobalVariableManager implements Manageable { return CONFIG_SECTION_NAME; } - @Override - public boolean supportsParsingObject() { - return true; - } - @Override public void parseObject(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Object object) throws LocalizedException { if (object != null) { 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 44930a9fc..7edb1900e 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 @@ -12,6 +12,7 @@ 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.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.gui.*; @@ -95,7 +96,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return Optional.ofNullable(this.byId.get(key)); } - public class CategoryParser implements ConfigParser { + public class CategoryParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"categories", "category"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java index d4ec4c773..7c95068a7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManager.java @@ -50,8 +50,6 @@ public interface TranslationManager extends Manageable { return miniMessageTranslation(key, null); } - void forcedLocale(Locale locale); - String miniMessageTranslation(String key, @Nullable Locale locale); default Component render(Component component) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index 041436ec6..f1e119a26 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -7,9 +7,7 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.Plugin; import net.momirealms.craftengine.core.plugin.PluginProperties; -import net.momirealms.craftengine.core.plugin.config.ConfigParser; -import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; -import net.momirealms.craftengine.core.plugin.config.TranslationConfigConstructor; +import net.momirealms.craftengine.core.plugin.config.*; import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag; import net.momirealms.craftengine.core.util.AdventureHelper; import org.jetbrains.annotations.NotNull; @@ -38,7 +36,6 @@ public class TranslationManagerImpl implements TranslationManager { private final String langVersion; private final String[] supportedLanguages; private final Map translationFallback = new LinkedHashMap<>(); - private Locale forcedLocale = null; private Locale selectedLocale = DEFAULT_LOCALE; private MiniMessageTranslationRegistry registry; private final Map clientLangData = new HashMap<>(); @@ -67,11 +64,6 @@ public class TranslationManagerImpl implements TranslationManager { return new ConfigParser[] {this.langParser, this.i18nParser}; } - @Override - public void forcedLocale(Locale locale) { - this.forcedLocale = locale; - } - @Override public void delayedLoad() { this.clientLangData.values().forEach(I18NData::processTranslations); @@ -98,8 +90,8 @@ public class TranslationManagerImpl implements TranslationManager { } private void setSelectedLocale() { - if (this.forcedLocale != null) { - this.selectedLocale = forcedLocale; + if (Config.forcedLocale() != null) { + this.selectedLocale = Config.forcedLocale(); return; } @@ -251,7 +243,7 @@ public class TranslationManagerImpl implements TranslationManager { } } - public class I18NParser implements ConfigParser { + public class I18NParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"}; @Override @@ -282,7 +274,7 @@ public class TranslationManagerImpl implements TranslationManager { } } - public class LangParser implements ConfigParser { + public class LangParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"}; @Override 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 index 9ac5d509d..49dcb3ef7 100644 --- 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 @@ -11,6 +11,7 @@ public enum Debugger { FURNITURE(Config::debugFurniture), RESOURCE_PACK(Config::debugResourcePack), ITEM(Config::debugItem), + BLOCK(Config::debugBlock), BLOCK_ENTITY(Config::debugBlockEntity); private final Supplier condition; 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 baa955b1a..501200a8a 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 @@ -97,6 +97,7 @@ public interface NetWorkUser { void removeTrackedChunk(long chunkPos); + @Nullable IntIdentityList clientBlockList(); void setClientBlockList(IntIdentityList integers); 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 a0892da26..6ca57ab61 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 @@ -5,6 +5,7 @@ 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.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; @@ -65,7 +66,7 @@ public abstract class AbstractSoundManager implements SoundManager { protected abstract void registerSounds(Collection sounds); - public class SongParser implements ConfigParser { + public class SongParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "jukebox_song", "jukebox-songs", "jukebox-song"}; @Override @@ -92,7 +93,7 @@ public abstract class AbstractSoundManager implements SoundManager { } } - public class SoundParser implements ConfigParser { + public class SoundParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"sounds", "sound"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundData.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundData.java index 949b5cf74..339c860ae 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundData.java @@ -10,6 +10,7 @@ import java.util.Optional; import java.util.function.Supplier; public record SoundData(Key id, SoundValue volume, SoundValue pitch) { + public static final SoundData EMPTY = new SoundData(Key.of("minecraft:intentionally_empty"), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1); public static SoundData create(Object obj, SoundValue volume, SoundValue pitch) { if (obj instanceof String key) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Instrument.java b/core/src/main/java/net/momirealms/craftengine/core/util/Instrument.java index 7c1f60dad..a43d10a2a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Instrument.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Instrument.java @@ -34,4 +34,6 @@ public enum Instrument { public String id() { return id; } + + public static final Instrument[] VALUES = Instrument.values(); } From 67ff30dceab10a60dd714e7c9f15b6c0afa8c9fa Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 27 Sep 2025 01:12:01 +0800 Subject: [PATCH 067/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=8A=A8id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/pack/cache/AutoId.java | 200 ++++++++++++++++++ .../core/pack/cache/AutoIdCache.java | 27 --- 2 files changed, 200 insertions(+), 27 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoId.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoIdCache.java diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoId.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoId.java new file mode 100644 index 000000000..15e4cf7fc --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoId.java @@ -0,0 +1,200 @@ +package net.momirealms.craftengine.core.pack.cache; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import net.momirealms.craftengine.core.util.FileUtils; +import net.momirealms.craftengine.core.util.GsonHelper; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; + +public class AutoId { + private final Path cachePath; + private final BiMap forcedIds = HashBiMap.create(128); + + private final Map cachedIds = new HashMap<>(); + private final BitSet occupiedIds = new BitSet(); + private final Map> autoIds = new HashMap<>(); + private int currentAutoId; + private int minId; + private int maxId; + + public AutoId(Path cachePath) { + this.cachePath = cachePath; + } + + public void reset(int startIndex, int endIndex) { + this.minId = startIndex; + this.currentAutoId = startIndex; + this.maxId = endIndex; + this.occupiedIds.clear(); + this.forcedIds.clear(); + this.autoIds.clear(); + this.cachedIds.clear(); + } + + public void arrangeForTheRest() { + // 然后处理自动分配的ID + for (Map.Entry> entry : this.autoIds.entrySet()) { + String name = entry.getKey(); + CompletableFuture future = entry.getValue(); + + // 不应该触发 + if (future.isDone()) { + continue; + } + + // 尝试使用缓存的ID,并且其有效 + Integer cachedId = this.cachedIds.get(name); + if (cachedId != null && !this.occupiedIds.get(cachedId) && cachedId >= this.minId && cachedId <= this.maxId) { + this.occupiedIds.set(cachedId); + future.complete(cachedId); + continue; + } + + // 寻找下一个可用的自动ID + int autoId = findNextAvailableAutoId(); + if (autoId == -1) { + // 没有可用的ID + future.completeExceptionally(new AutoIdExhaustedException(name, this.minId, this.maxId)); + continue; + } + + // 分配找到的ID + this.occupiedIds.set(autoId); + future.complete(autoId); + this.cachedIds.put(name, autoId); + } + + // 清空futureIds,因为所有请求都已处理 + this.autoIds.clear(); + } + + private int findNextAvailableAutoId() { + // 如果已经用尽 + if (this.currentAutoId > this.maxId) { + return -1; + } + // 寻找下一个可用的id + this.currentAutoId = this.occupiedIds.nextClearBit(this.currentAutoId); + // 已经用完了 + if (this.currentAutoId > maxId) { + return -1; + } + // 找到了 + return this.currentAutoId; + } + + // 强制使用某个id,这时候直接标记到occupiedIds,如果被占用,则直接抛出异常 + public CompletableFuture forceId(final String name, int index) { + // 检查ID是否在有效范围内,一般不会在这触发 + if (index < this.minId || index > this.maxId) { + return CompletableFuture.failedFuture(new AutoIdOutOfRangeException(name, index, this.minId, this.maxId)); + } + + // 检查ID是否已被其他名称占用 + String previous = this.forcedIds.inverse().get(index); + if (previous != null && !previous.equals(name)) { + return CompletableFuture.failedFuture(new AutoIdConflictException(previous, index)); + } + + this.forcedIds.put(name, index); + this.cachedIds.remove(name); // 如果曾经被缓存过,那么移除 + return CompletableFuture.completedFuture(index); + } + + // 自动分配id,优先使用缓存的值 + public CompletableFuture autoId(final String name) { + CompletableFuture future = new CompletableFuture<>(); + this.autoIds.put(name, future); + return future; + } + + // 大多数时候通过指令,移除那些已经不再被使用的id,使用完以后记得调用saveCache以保存更改 + public int clearUnusedIds(Predicate predicate) { + List toRemove = new ArrayList<>(); + for (String id : this.cachedIds.keySet()) { + if (predicate.test(id)) { + toRemove.add(id); + } + } + for (String id : toRemove) { + Integer removedId = this.cachedIds.remove(id); + if (removedId != null) { + // 只有当这个ID不是强制ID时才从occupiedIds中移除 + if (!forcedIds.containsValue(removedId)) { + occupiedIds.clear(removedId); + } + } + } + return toRemove.size(); + } + + // 获取已分配的ID(用于调试或查询) + public Integer getId(String name) { + if (forcedIds.containsKey(name)) { + return forcedIds.get(name); + } + return cachedIds.get(name); + } + + // 获取所有已分配的ID映射 + public Map getAllocatedIds() { + Map result = new HashMap<>(); + result.putAll(forcedIds); + result.putAll(cachedIds); + return Collections.unmodifiableMap(result); + } + + // 检查某个ID是否已被占用 + public boolean isIdOccupied(int id) { + return occupiedIds.get(id); + } + + // 从缓存中加载文件 + public void loadCache() throws IOException { + if (!Files.exists(this.cachePath)) { + return; + } + JsonElement element = GsonHelper.readJsonFile(this.cachePath); + if (element instanceof JsonObject jsonObject) { + for (Map.Entry entry : jsonObject.entrySet()) { + if (entry.getValue() instanceof JsonPrimitive primitive) { + int id = primitive.getAsInt(); + this.cachedIds.put(entry.getKey(), id); + } + } + } + } + + // 保存缓存到文件 + public void saveCache() throws IOException { + FileUtils.createDirectoriesSafe(this.cachePath.getParent()); + GsonHelper.writeJsonFile(GsonHelper.get().toJsonTree(this.cachedIds), this.cachePath); + } + + public static class AutoIdConflictException extends RuntimeException { + public AutoIdConflictException(String previousOwner, int id) { + super("ID " + id + " is already occupied by: " + previousOwner); + } + } + + public static class AutoIdOutOfRangeException extends RuntimeException { + public AutoIdOutOfRangeException(String name, int id, int min, int max) { + super("ID " + id + " for '" + name + "' is out of range. Valid range: " + min + "-" + max); + } + } + + public static class AutoIdExhaustedException extends RuntimeException { + public AutoIdExhaustedException(String name, int min, int max) { + super("No available auto ID for '" + name + "'. All IDs in range " + min + "-" + max + " are occupied."); + } + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoIdCache.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoIdCache.java deleted file mode 100644 index 1588a2d1b..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoIdCache.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.momirealms.craftengine.core.pack.cache; - -import java.util.BitSet; -import java.util.HashMap; -import java.util.Map; - -public class AutoIdCache { - private final Map forcedIds = new HashMap<>(); - private final Map cachedIds = new HashMap<>(); - private final BitSet occupiedIds = new BitSet(); - private int currentAutoId; - - public AutoIdCache(int startIndex) { - this.currentAutoId = startIndex; - } - - public boolean setForcedId(final String name, int index) { - if (this.occupiedIds.get(index)) { - return false; - } - this.occupiedIds.set(index); - this.forcedIds.put(name, index); - return true; - } - - -} From 511db380f3a80dede46f6691fd4581d8152a489d Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 27 Sep 2025 03:23:01 +0800 Subject: [PATCH 068/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A3=B0=E9=9F=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BlockEventListener.java | 6 +- .../behavior/FlintAndSteelItemBehavior.java | 10 ++-- .../plugin/network/BukkitNetworkManager.java | 59 +++++++++++++------ .../plugin/user/BukkitServerPlayer.java | 4 +- .../core/entity/player/Player.java | 17 +++++- 5 files changed, 67 insertions(+), 29 deletions(-) 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 1daab5e9d..4b6dd1711 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.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.sound.SoundSource; import net.momirealms.craftengine.core.util.Cancellable; import net.momirealms.craftengine.core.util.ItemUtils; import net.momirealms.craftengine.core.util.VersionHelper; @@ -168,7 +169,7 @@ public final class BlockEventListener implements Listener { } // play sound - world.playBlockSound(position, state.settings().sounds().breakSound()); + serverPlayer.playSound(position, state.settings().sounds().breakSound(), SoundSource.BLOCK); } } else { // override vanilla block loots @@ -193,7 +194,6 @@ public final class BlockEventListener implements Listener { } }); } - // sound system if (Config.enableSoundSystem()) { Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); @@ -201,7 +201,7 @@ public final class BlockEventListener implements Listener { try { Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock); Object breakSound = CoreReflections.field$SoundType$breakSound.get(soundType); - block.getWorld().playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f); + player.playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f); } catch (ReflectiveOperationException e) { this.plugin.logger().warn("Failed to get sound type", e); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java index 2be578ff4..df3e667e0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java @@ -90,7 +90,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { } // 且没有shift if (!player.isSecondaryUseActive()) { - player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.playSound(firePos, FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); } } else { // 玩家觉得自定义方块不可燃,且点击了侧面,那么就要判断火源下方的方块是否可燃,如果不可燃,则补发声音 @@ -113,16 +113,16 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { if (player.isSecondaryUseActive()) { // 如果底部不能燃烧,则燃烧点位为侧面,需要补发 if (!belowCanBurn) { - player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.playSound(firePos, FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); player.swingHand(context.getHand()); } } else { - player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.playSound(firePos, FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); } } else { // 如果底部方块不可燃烧才补发 if (!belowCanBurn) { - player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.playSound(firePos, FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); player.swingHand(context.getHand()); } } @@ -153,7 +153,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { } } } - player.playSound(FLINT_SOUND, firePos, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); + player.playSound(firePos, FLINT_SOUND, SoundSource.BLOCK, 1f, RandomUtils.generateRandomFloat(0.8f, 1.2f)); player.swingHand(context.getHand()); } return InteractionResult.PASS; 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 7ced7ec1b..109ecadc9 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 @@ -50,6 +50,7 @@ import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.advancement.network.AdvancementHolder; import net.momirealms.craftengine.core.advancement.network.AdvancementProgress; +import net.momirealms.craftengine.core.block.BlockSounds; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.font.FontManager; @@ -2286,28 +2287,50 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes int state = buf.readInt(); boolean global = buf.readBoolean(); int newState = user.clientModEnabled() ? modBlockStateMapper[state] : blockStateMapper[state]; - Object blockState = BlockStateUtils.idToBlockState(newState); - Object block = BlockStateUtils.getBlockOwner(blockState); - if (BukkitBlockManager.instance().isBlockSoundRemoved(block) && !FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) { + if (BlockStateUtils.isVanillaBlock(state)) { + Object blockState = BlockStateUtils.idToBlockState(state); + Object block = BlockStateUtils.getBlockOwner(blockState); + if (BukkitBlockManager.instance().isBlockSoundRemoved(block)) { + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); + Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString()); + Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId); + if (mappedSoundId != null) { + Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty()); + Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); + Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( + mappedBreakSoundHolder, + CoreReflections.instance$SoundSource$BLOCKS, + blockPos.x() + 0.5, + blockPos.y() + 0.5, + blockPos.z() + 0.5, + 1f, + 0.8F, + RandomUtils.generateRandomLong() + ); + user.sendPacket(packet, true); + } + } + } else { + Object blockState = BlockStateUtils.idToBlockState(state); Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString()); Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId); - if (mappedSoundId != null) { - Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty()); - Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); - Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( - mappedBreakSoundHolder, - CoreReflections.instance$SoundSource$BLOCKS, - blockPos.x() + 0.5, - blockPos.y() + 0.5, - blockPos.z() + 0.5, - (FastNMS.INSTANCE.field$SoundType$volume(soundType) + 1.0F) / 2.0F, - FastNMS.INSTANCE.field$SoundType$pitch(soundType) * 0.8F, - RandomUtils.generateRandomLong() - ); - user.sendPacket(packet, true); - } + Object finalSoundId = KeyUtils.toResourceLocation(mappedSoundId == null ? soundId : mappedSoundId); + Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(finalSoundId, Optional.empty()); + Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); + Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( + mappedBreakSoundHolder, + CoreReflections.instance$SoundSource$BLOCKS, + blockPos.x() + 0.5, + blockPos.y() + 0.5, + blockPos.z() + 0.5, + 1f, + 0.8F, + RandomUtils.generateRandomLong() + ); + user.sendPacket(packet, true); } if (newState == state) { return; 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 c08d6af2d..f2481c485 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 @@ -370,8 +370,8 @@ public class BukkitServerPlayer extends Player { } @Override - public void playSound(Key sound, BlockPos blockPos, SoundSource source, float volume, float pitch) { - platformPlayer().playSound(new Location(null, blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); + public void playSound(Position pos, Key sound, SoundSource source, float volume, float pitch) { + platformPlayer().playSound(new Location(null, pos.x(), pos.y(), pos.z()), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); } @Override 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 9a33c2dbc..6df8b25c7 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 @@ -6,9 +6,12 @@ import net.momirealms.craftengine.core.entity.AbstractEntity; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.context.CooldownData; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; +import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.BlockPos; +import net.momirealms.craftengine.core.world.Position; +import net.momirealms.craftengine.core.world.Vec3d; import net.momirealms.craftengine.core.world.WorldPosition; import org.jetbrains.annotations.NotNull; @@ -100,7 +103,19 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract void playSound(Key sound, SoundSource source, float volume, float pitch); - public abstract void playSound(Key sound, BlockPos pos, SoundSource source, float volume, float pitch); + public abstract void playSound(Position pos, Key sound, SoundSource source, float volume, float pitch); + + public void playSound(BlockPos pos, Key sound, SoundSource source, float volume, float pitch) { + this.playSound(Vec3d.atCenterOf(pos), sound, source, volume, pitch); + } + + public void playSound(BlockPos pos, SoundData data, SoundSource source) { + this.playSound(pos, data.id(), source, data.volume().get(), data.pitch().get()); + } + + public void playSound(Position pos, SoundData data, SoundSource source) { + this.playSound(pos, data.id(), source, data.volume().get(), data.pitch().get()); + } public abstract void giveItem(Item item); From a7a49dd9ce5bfbca074a5c8b4aa5e3ce447bc532 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 27 Sep 2025 03:23:15 +0800 Subject: [PATCH 069/125] =?UTF-8?q?=E6=B8=85=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/block/behavior/ChimeBlockBehavior.java | 2 -- .../craftengine/bukkit/plugin/network/BukkitNetworkManager.java | 1 - .../momirealms/craftengine/core/block/properties/Property.java | 1 - gradle.properties | 2 +- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java index 56e68b810..4b286d52e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChimeBlockBehavior.java @@ -10,10 +10,8 @@ import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.concurrent.Callable; -import java.util.stream.Stream; public class ChimeBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); 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 109ecadc9..0936fa242 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 @@ -50,7 +50,6 @@ import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.advancement.network.AdvancementHolder; import net.momirealms.craftengine.core.advancement.network.AdvancementProgress; -import net.momirealms.craftengine.core.block.BlockSounds; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.font.FontManager; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java index 233ad526b..fc3370fac 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.block.properties; -import com.google.common.base.MoreObjects; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; diff --git a/gradle.properties b/gradle.properties index f078e28e6..e56947eb0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.6 +project_version=0.0.63.7 config_version=46 lang_version=31 project_group=net.momirealms From e64a8d5fed10b8f35bb42701b380cf7f2532afb9 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 27 Sep 2025 18:32:02 +0800 Subject: [PATCH 070/125] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../advancement/BukkitAdvancementManager.java | 2 +- .../bukkit/item/behavior/AxeItemBehavior.java | 2 +- .../item/behavior/BlockItemBehavior.java | 6 +- .../behavior/CompostableItemBehavior.java | 2 +- .../behavior/DoubleHighBlockItemBehavior.java | 6 +- .../behavior/FlintAndSteelItemBehavior.java | 2 +- .../item/behavior/FurnitureItemBehavior.java | 6 +- .../LiquidCollisionBlockItemBehavior.java | 6 +- .../item/behavior/WallBlockItemBehavior.java | 6 +- .../bukkit/loot/BukkitVanillaLootManager.java | 2 +- common-files/src/main/resources/config.yml | 5 + .../core/block/AbstractBlockManager.java | 28 +- .../furniture/AbstractFurnitureManager.java | 2 +- .../core/font/AbstractFontManager.java | 42 +- .../core/item/AbstractItemManager.java | 559 ++++++++++-------- .../core/item/behavior/EmptyItemBehavior.java | 2 +- .../item/behavior/ItemBehaviorFactory.java | 2 +- .../core/item/behavior/ItemBehaviors.java | 23 +- .../item/recipe/AbstractRecipeManager.java | 4 +- .../core/pack/AbstractPackManager.java | 76 +-- .../craftengine/core/pack/cache/AutoId.java | 200 ------- .../core/pack/cache/IdAllocator.java | 226 +++++++ .../core/plugin/config/Config.java | 26 + .../plugin/config/IdObjectConfigParser.java | 2 +- .../plugin/config/IdSectionConfigParser.java | 2 +- .../config/template/TemplateManagerImpl.java | 4 +- .../plugin/context/GlobalVariableManager.java | 3 +- .../gui/category/ItemBrowserManagerImpl.java | 2 +- .../LocalizedResourceConfigException.java | 2 +- .../plugin/locale/TranslationManagerImpl.java | 6 +- .../core/sound/AbstractSoundManager.java | 4 +- .../core/util/ResourceConfigUtils.java | 30 + 32 files changed, 715 insertions(+), 575 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoId.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java index 1cbff1a44..ee34b3993 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java @@ -120,7 +120,7 @@ public class BukkitAdvancementManager extends AbstractAdvancementManager { } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (advancements.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.advancement.duplicate", path, id); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index e928f9233..2cca3f5ae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -131,7 +131,7 @@ public class AxeItemBehavior extends ItemBehavior { public static class Factory implements ItemBehaviorFactory { @Override - public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { return INSTANCE; } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index 45d9c1ef7..a71c46f64 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -234,7 +234,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { public static class Factory implements ItemBehaviorFactory { @Override - public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { Object id = arguments.get("block"); if (id == null) { throw new LocalizedResourceConfigException("warning.config.item.behavior.block.missing_block", new IllegalArgumentException("Missing required parameter 'block' for block_item behavior")); @@ -242,9 +242,9 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); } return new BlockItemBehavior(key); } else { 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 e4d92d241..50015c355 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 @@ -79,7 +79,7 @@ public class CompostableItemBehavior extends ItemBehavior { public static class Factory implements ItemBehaviorFactory { @Override - public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { double chance = ResourceConfigUtils.getAsDouble(arguments.getOrDefault("chance", 0.55), "chance"); return new CompostableItemBehavior(chance); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java index 122bb18b4..403d8eea3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java @@ -40,7 +40,7 @@ public class DoubleHighBlockItemBehavior extends BlockItemBehavior { public static class Factory implements ItemBehaviorFactory { @Override - public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { Object id = arguments.get("block"); if (id == null) { throw new LocalizedResourceConfigException("warning.config.item.behavior.double_high.missing_block", new IllegalArgumentException("Missing required parameter 'block' for double_high_block_item behavior")); @@ -48,9 +48,9 @@ public class DoubleHighBlockItemBehavior extends BlockItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); } return new DoubleHighBlockItemBehavior(key); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java index df3e667e0..db9c29878 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/FlintAndSteelItemBehavior.java @@ -161,7 +161,7 @@ public class FlintAndSteelItemBehavior extends ItemBehavior { public static class Factory implements ItemBehaviorFactory { @Override - public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { + public ItemBehavior create(Pack pack, Path path, String node, Key id, Map arguments) { return INSTANCE; } } 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 c7caee0a0..82a1f8457 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 @@ -177,7 +177,7 @@ public class FurnitureItemBehavior extends ItemBehavior { public static class Factory implements ItemBehaviorFactory { @Override - public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { Object id = arguments.get("furniture"); if (id == null) { throw new LocalizedResourceConfigException("warning.config.item.behavior.furniture.missing_furniture", new IllegalArgumentException("Missing required parameter 'furniture' for furniture_item behavior")); @@ -185,9 +185,9 @@ public class FurnitureItemBehavior extends ItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitFurnitureManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitFurnitureManager.instance().parser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); } else { - BukkitFurnitureManager.instance().parser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitFurnitureManager.instance().parser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); } return new FurnitureItemBehavior(key); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java index 9e058c549..11a852cac 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/LiquidCollisionBlockItemBehavior.java @@ -70,7 +70,7 @@ public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior { public static class Factory implements ItemBehaviorFactory { @Override - public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { Object id = arguments.get("block"); if (id == null) { throw new LocalizedResourceConfigException("warning.config.item.behavior.liquid_collision.missing_block", new IllegalArgumentException("Missing required parameter 'block' for liquid_collision_block_item behavior")); @@ -79,9 +79,9 @@ public class LiquidCollisionBlockItemBehavior extends BlockItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); } return new LiquidCollisionBlockItemBehavior(key, offset); } else { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java index bbc48120b..8f8232d4f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java @@ -35,7 +35,7 @@ public class WallBlockItemBehavior extends BlockItemBehavior { public static class Factory implements ItemBehaviorFactory { @Override - public ItemBehavior create(Pack pack, Path path, Key key, Map arguments) { + public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { Object id = arguments.get("block"); if (id == null) { throw new LocalizedResourceConfigException("warning.config.item.behavior.wall_block.missing_block", new IllegalArgumentException("Missing required parameter 'block' for wall_block_item behavior")); @@ -43,9 +43,9 @@ public class WallBlockItemBehavior extends BlockItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, key, MiscUtils.castToMap(map, false)); + BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); } return new WallBlockItemBehavior(key); } else { 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 31ae7e70d..805808e92 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 @@ -105,7 +105,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("type"), "warning.config.vanilla_loot.missing_type"); VanillaLoot.Type typeEnum; try { diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 6a773846c..4f14758e1 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -150,6 +150,11 @@ item: click-in-inventory: false # this option won't work for players in creative mode drop: false pick-up: false + # Decided the starting value for automatic custom model data assignment. + custom-model-data-starting-value: + default: 10000 + overrides: + paper: 20000 equipment: # The sacrificed-vanilla-armor argument determines which vanilla armor gets completely removed (loses all its trims) diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index aeeebaea8..9cb662404 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -20,7 +20,6 @@ import net.momirealms.craftengine.core.plugin.config.*; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; @@ -238,6 +237,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem @Override public void parseSection(Pack pack, Path path, Map section) throws LocalizedException { + ExceptionCollector exceptionCollector = new ExceptionCollector<>(); for (Map.Entry entry : section.entrySet()) { String before = entry.getKey(); String after = entry.getValue().toString(); @@ -245,21 +245,25 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem BlockStateWrapper beforeState = createVanillaBlockState(before); BlockStateWrapper afterState = createVanillaBlockState(before); if (beforeState == null) { - TranslationManager.instance().log("warning.config.block_state_mapping.invalid_state", path.toString(), before); - return; + exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block_state_mapping.invalid_state", before)); + continue; } if (afterState == null) { - TranslationManager.instance().log("warning.config.block_state_mapping.invalid_state", path.toString(), after); - return; + exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block_state_mapping.invalid_state", after)); + continue; } int previous = AbstractBlockManager.this.blockStateMappings[beforeState.registryId()]; if (previous != -1 && previous != afterState.registryId()) { - TranslationManager.instance().log("warning.config.block_state_mapping.conflict", path.toString(), beforeState.toString(), afterState.toString(), BlockRegistryMirror.byId(previous).toString()); - return; + exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block_state_mapping.conflict", + beforeState.toString(), + afterState.toString(), + BlockRegistryMirror.byId(previous).toString())); + continue; } AbstractBlockManager.this.blockStateMappings[beforeState.registryId()] = afterState.registryId(); AbstractBlockManager.this.blockStateArranger.computeIfAbsent(getBlockOwnerId(beforeState), k -> new ArrayList<>()).add(afterState); } + exceptionCollector.throwIfPresent(); } } @@ -277,19 +281,19 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (isVanillaBlock(id)) { - parseVanillaBlock(pack, path, id, section); + parseVanillaBlock(id, section); } else { // check duplicated config if (AbstractBlockManager.this.byId.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.block.duplicate"); } - parseCustomBlock(pack, path, id, section); + parseCustomBlock(id, section); } } - private void parseVanillaBlock(Pack pack, Path path, Key id, Map section) { + private void parseVanillaBlock(Key id, Map section) { Map settings = MiscUtils.castToMap(section.get("settings"), true); if (settings != null) { Object clientBoundTags = settings.get("client-bound-tags"); @@ -300,7 +304,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } - private void parseCustomBlock(Pack pack, Path path, Key id, Map section) { + private void parseCustomBlock(Key id, Map section) { // 获取方块设置 BlockSettings settings = BlockSettings.fromMap(id, MiscUtils.castToMap(section.get("settings"), true)); // 读取基础外观配置 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 3794e85f2..0d5a714d9 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 @@ -89,7 +89,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { @SuppressWarnings("unchecked") @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (byId.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.furniture.duplicate"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 11ef5e872..89721f922 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -386,18 +386,18 @@ public abstract class AbstractFontManager implements FontManager { } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (emojis.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.emoji.duplicate", path, id); + throw new LocalizedResourceConfigException("warning.config.emoji.duplicate"); } String permission = (String) section.get("permission"); Object keywordsRaw = section.get("keywords"); if (keywordsRaw == null) { - throw new LocalizedResourceConfigException("warning.config.emoji.missing_keywords", path, id); + throw new LocalizedResourceConfigException("warning.config.emoji.missing_keywords"); } List keywords = MiscUtils.getAsStringList(keywordsRaw); if (keywords.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.emoji.missing_keywords", path, id); + throw new LocalizedResourceConfigException("warning.config.emoji.missing_keywords"); } Object rawContent = section.getOrDefault("content", ""); String content; @@ -416,7 +416,7 @@ public abstract class AbstractFontManager implements FontManager { if (bitmapImage.isPresent()) { image = bitmapImage.get().miniMessageAt(0, 0); } else { - throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); + throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", rawImage); } } else if (split.length == 4) { Key imageId = new Key(split[0], split[1]); @@ -425,13 +425,13 @@ public abstract class AbstractFontManager implements FontManager { try { image = bitmapImage.get().miniMessageAt(Integer.parseInt(split[2]), Integer.parseInt(split[3])); } catch (ArrayIndexOutOfBoundsException e) { - throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); + throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", rawImage); } } else { - throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); + throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", rawImage); } } else { - throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", path, id, rawImage); + throw new LocalizedResourceConfigException("warning.config.emoji.invalid_image", rawImage); } } Emoji emoji = new Emoji(content, permission, image, keywords); @@ -453,24 +453,24 @@ public abstract class AbstractFontManager implements FontManager { } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (images.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.image.duplicate", path, id); + throw new LocalizedResourceConfigException("warning.config.image.duplicate"); } Object file = section.get("file"); if (file == null) { - throw new LocalizedResourceConfigException("warning.config.image.missing_file", path, id); + throw new LocalizedResourceConfigException("warning.config.image.missing_file"); } String resourceLocation = CharacterUtils.replaceBackslashWithSlash(file.toString()); if (!ResourceLocation.isValid(resourceLocation)) { - throw new LocalizedResourceConfigException("warning.config.image.invalid_file_chars", path, id, resourceLocation); + throw new LocalizedResourceConfigException("warning.config.image.invalid_file_chars", resourceLocation); } String fontName = section.getOrDefault("font", "minecraft:default").toString(); if (!ResourceLocation.isValid(fontName)) { - throw new LocalizedResourceConfigException("warning.config.image.invalid_font_chars", path, id, fontName); + throw new LocalizedResourceConfigException("warning.config.image.invalid_font_chars", fontName); } Key fontKey = Key.withDefaultNamespace(fontName, id.namespace()); @@ -478,7 +478,7 @@ public abstract class AbstractFontManager implements FontManager { List chars; Object charsObj = ResourceConfigUtils.get(section, "chars", "char"); if (charsObj == null) { - throw new LocalizedResourceConfigException("warning.config.image.missing_char", path, id); + throw new LocalizedResourceConfigException("warning.config.image.missing_char"); } if (charsObj instanceof List list) { chars = MiscUtils.getAsStringList(list).stream().map(it -> { @@ -489,7 +489,7 @@ public abstract class AbstractFontManager implements FontManager { } }).toList(); if (chars.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.image.missing_char", path, id); + throw new LocalizedResourceConfigException("warning.config.image.missing_char"); } } else { if (charsObj instanceof Integer integer) { @@ -497,7 +497,7 @@ public abstract class AbstractFontManager implements FontManager { } else { String character = charsObj.toString(); if (character.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.image.missing_char", path, id); + throw new LocalizedResourceConfigException("warning.config.image.missing_char"); } if (character.length() == 1) { chars = List.of(character.toCharArray()); @@ -522,7 +522,7 @@ public abstract class AbstractFontManager implements FontManager { for (int codepoint : codepoints) { if (font.isCodepointInUse(codepoint)) { BitmapImage image = font.bitmapImageByCodepoint(codepoint); - throw new LocalizedResourceConfigException("warning.config.image.codepoint_conflict", path, id, + throw new LocalizedResourceConfigException("warning.config.image.codepoint_conflict", fontKey.toString(), CharacterUtils.encodeCharsToUnicode(Character.toChars(codepoint)), new String(Character.toChars(codepoint)), @@ -530,12 +530,12 @@ public abstract class AbstractFontManager implements FontManager { } } if (codepoints.length == 0) { - throw new LocalizedResourceConfigException("warning.config.image.missing_char", path, id); + throw new LocalizedResourceConfigException("warning.config.image.missing_char"); } codepointGrid[i] = codepoints; if (size == -1) size = codepoints.length; if (size != codepoints.length) { - throw new LocalizedResourceConfigException("warning.config.image.invalid_codepoint_grid", path, id); + throw new LocalizedResourceConfigException("warning.config.image.invalid_codepoint_grid"); } } @@ -558,14 +558,14 @@ public abstract class AbstractFontManager implements FontManager { return; } } else { - throw new LocalizedResourceConfigException("warning.config.image.missing_height", path, id); + throw new LocalizedResourceConfigException("warning.config.image.missing_height"); } } int height = ResourceConfigUtils.getAsInt(heightObj, "height"); int ascent = ResourceConfigUtils.getAsInt(section.getOrDefault("ascent", height - 1), "ascent"); if (height < ascent) { - throw new LocalizedResourceConfigException("warning.config.image.height_ascent_conflict", path, id, String.valueOf(height), String.valueOf(ascent)); + throw new LocalizedResourceConfigException("warning.config.image.height_ascent_conflict", String.valueOf(height), String.valueOf(ascent)); } BitmapImage bitmapImage = new BitmapImage(id, fontKey, height, ascent, resourceLocation, codepointGrid); 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 75b4e4038..b31c26ff3 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 @@ -14,6 +14,7 @@ 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.cache.IdAllocator; 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; @@ -32,8 +33,10 @@ import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.type.Either; +import java.io.IOException; import java.nio.file.Path; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Stream; @@ -282,7 +285,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (AbstractItemManager.this.equipments.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.equipment.duplicate"); } @@ -313,6 +316,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl public class ItemParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; + private final Map idAllocators = new HashMap<>(); private boolean isModernFormatRequired() { return Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_4); @@ -322,6 +326,18 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return Config.packMinVersion().isBelow(MinecraftVersions.V1_21_4); } + private boolean needsCustomModelDataCompatibility() { + return Config.packMinVersion().isBelow(MinecraftVersions.V1_21_2); + } + + private boolean needsItemModelCompatibility() { + return Config.packMaxVersion().isAbove(MinecraftVersions.V1_21_2); + } + + public Map idAllocators() { + return this.idAllocators; + } + @Override public String[] sectionId() { return CONFIG_SECTION_NAME; @@ -333,261 +349,326 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void preProcess() { + this.idAllocators.clear(); + } + + @Override + public void postProcess() { + for (Map.Entry entry : this.idAllocators.entrySet()) { + entry.getValue().processPendingAllocations(); + try { + entry.getValue().saveToCache(); + } catch (IOException e) { + AbstractItemManager.this.plugin.logger().warn("Error while saving custom model data allocation for material " + entry.getKey().asString(), e); + } + } + } + + // 创建或获取已有的自动分配器 + private IdAllocator getOrCreateIdAllocator(Key key) { + return this.idAllocators.computeIfAbsent(key, k -> { + IdAllocator newAllocator = new IdAllocator(plugin.dataFolderPath().resolve("cache").resolve("custom-model-data").resolve(k.value() + ".json")); + newAllocator.reset(Config.customModelDataStartingValue(k), 16_777_216); + try { + newAllocator.loadFromCache(); + } catch (IOException e) { + AbstractItemManager.this.plugin.logger().warn("Error while loading custom model data from cache for material " + k.asString(), e); + } + return newAllocator; + }); + } + + @Override + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (AbstractItemManager.this.customItemsById.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.item.duplicate"); } - + // 创建UniqueKey,仅缓存用 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; - // 如果是原版物品,那么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-model"), "client-bound-model") : Config.globalClientboundModel(); - if (customModelData < 0) { - throw new LocalizedResourceConfigException("warning.config.item.invalid_custom_model_data", String.valueOf(customModelData)); - } - if (customModelData > 16_777_216) { - throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); - } - // item-model值 - Key itemModelKey = null; + // 读取服务端侧材质 + Key material = isVanillaItem ? id : Key.from(ResourceConfigUtils.requireNonEmptyStringOrThrow(section.get("material"), "warning.config.item.missing_material").toLowerCase(Locale.ROOT)); + // 读取客户端侧材质 + Key clientBoundMaterial = VersionHelper.PREMIUM && section.containsKey("client-bound-material") ? Key.from(section.get("client-bound-material").toString().toLowerCase(Locale.ROOT)) : material; - CustomItem.Builder itemBuilder = createPlatformItemBuilder(uniqueId, material, clientBoundMaterial); - boolean hasItemModelSection = section.containsKey("item-model"); + // custom model data + CompletableFuture customModelDataFuture; - // 如果custom-model-data不为0 - if (customModelData > 0) { - if (clientBoundModel) itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData)); - else itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); - } - // 如果没有item-model选项被配置,同时这个物品又含有 model 区域 - else if (!hasItemModelSection && section.containsKey("model") && VersionHelper.isOrAbove1_21_2()) { - // 那么使用物品id当成item-model的值 - itemModelKey = Key.from(section.getOrDefault("item-model", id.toString()).toString()); - // 但是有个前提,id必须是有效的resource location - if (ResourceLocation.isValid(itemModelKey.toString())) { - 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()); - if (clientBoundModel) itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModelKey)); - else itemBuilder.dataModifier(new ItemModelModifier<>(itemModelKey)); - } - - // 对于不重要的配置,可以仅警告,不返回 - ExceptionCollector collector = new ExceptionCollector<>(); - - // 应用物品数据 - try { - applyDataModifiers(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); - } catch (LocalizedResourceConfigException e) { - collector.add(e); - } - // 应用客户端侧数据 - try { - if (VersionHelper.PREMIUM) { - applyDataModifiers(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); - } - } catch (LocalizedResourceConfigException e) { - collector.add(e); - } - - // 如果不是原版物品,那么加入ce的标识符 - if (!isVanillaItem) - itemBuilder.dataModifier(new IdModifier<>(id)); - - // 事件 - Map>> eventTriggerListMap; - try { - eventTriggerListMap = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); - } catch (LocalizedResourceConfigException e) { - collector.add(e); - eventTriggerListMap = Map.of(); - } - - // 设置 - ItemSettings settings; - try { - settings = Optional.ofNullable(ResourceConfigUtils.get(section, "settings")) - .map(map -> ItemSettings.fromMap(MiscUtils.castToMap(map, true))) - .map(it -> isVanillaItem ? it.canPlaceRelatedVanillaBlock(true) : it) - .orElse(ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem)); - } catch (LocalizedResourceConfigException e) { - collector.add(e); - settings = ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem); - } - - // 行为 - List behaviors; - try { - behaviors = ItemBehaviors.fromObj(pack, path, id, ResourceConfigUtils.get(section, "behavior", "behaviors")); - } catch (LocalizedResourceConfigException e) { - collector.add(e); - behaviors = Collections.emptyList(); - } - - // 如果有物品更新器 - if (section.containsKey("updater")) { - Map updater = ResourceConfigUtils.getAsMap(section.get("updater"), "updater"); - List versions = new ArrayList<>(2); - for (Map.Entry entry : updater.entrySet()) { - try { - int version = Integer.parseInt(entry.getKey()); - versions.add(new ItemUpdateConfig.Version( - version, - ResourceConfigUtils.parseConfigAsList(entry.getValue(), map -> ItemUpdaters.fromMap(id, map)).toArray(new ItemUpdater[0]) - )); - } catch (NumberFormatException ignored) { - } - } - ItemUpdateConfig config = new ItemUpdateConfig(versions); - itemBuilder.updater(config); - itemBuilder.dataModifier(new ItemVersionModifier<>(config.maxVersion())); - } - - // 构建自定义物品 - CustomItem customItem = itemBuilder - .isVanillaItem(isVanillaItem) - .behaviors(behaviors) - .settings(settings) - .events(eventTriggerListMap) - .build(); - - // 添加到缓存 - addCustomItem(customItem); - - // 如果有类别,则添加 - if (section.containsKey("category")) { - AbstractItemManager.this.plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); - } - - // 模型配置区域,如果这里被配置了,那么用户必须要配置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) { - collector.throwIfPresent(); - return; - } - - boolean needsModelSection = isModernFormatRequired() || (needsLegacyCompatibility() && legacyModelSection == null); - // 只对自定义物品有这个限制 if (!isVanillaItem) { - // 既没有模型值也没有item-model - if (customModelData == 0 && itemModelKey == null) { - collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model_id")); + // 如果用户指定了,说明要手动分配,不管他是什么版本,都强制设置模型值 + if (section.containsKey("custom-model-data")) { + int customModelData = ResourceConfigUtils.getAsInt(section.getOrDefault("custom-model-data", 0), "custom-model-data"); + if (customModelData < 0) { + throw new LocalizedResourceConfigException("warning.config.item.invalid_custom_model_data", String.valueOf(customModelData)); + } + if (customModelData > 16_777_216) { + throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); + } + customModelDataFuture = getOrCreateIdAllocator(clientBoundMaterial).assignFixedId(id.asString(), customModelData); } - } - - // 新版格式 - ItemModel modernModel = null; - // 旧版格式 - TreeSet legacyOverridesModels = null; - // 如果需要支持新版item model 或者用户需要旧版本兼容,但是没配置legacy-model - if (needsModelSection) { - // 1.21.4+必须要配置model区域,如果不需要高版本兼容,则可以只写legacy-model - if (modelSection == null) { - collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model")); - return; - } - try { - modernModel = ItemModels.fromMap(modelSection); - for (ModelGeneration generation : modernModel.modelsToGenerate()) { - prepareModelGeneration(generation); + // 用户没指定custom-model-data,则看当前资源包版本兼容需求 + else { + // 如果最低版本要1.21.1以下支持 + if (needsCustomModelDataCompatibility()) { + customModelDataFuture = getOrCreateIdAllocator(clientBoundMaterial).requestAutoId(id.asString()); } - } catch (LocalizedResourceConfigException e) { - collector.addAndThrow(e); - } - } - // 如果需要旧版本兼容 - if (needsLegacyCompatibility()) { - if (legacyModelSection != null) { - try { - LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection, customModelData); - for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) { - prepareModelGeneration(generation); - } - legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides()); - } catch (LocalizedResourceConfigException e) { - collector.addAndThrow(e); - } - } else { - legacyOverridesModels = new TreeSet<>(); - processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, clientBoundMaterial, customModelData); - if (legacyOverridesModels.isEmpty()) { - collector.add(new LocalizedResourceConfigException("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString())); - } - } - } - - // 自定义物品的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)) { - collector.addAndThrow(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) { - collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.item_model.conflict", itemModelKey.asString())); - } - - // 使用了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 { + customModelDataFuture = CompletableFuture.completedFuture(0); } } } 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") - )); - } + // 原版物品不应该有这个 + customModelDataFuture = CompletableFuture.completedFuture(0); } - // 抛出异常 - collector.throwIfPresent(); + // 是否使用客户端侧模型 + boolean clientBoundModel = VersionHelper.PREMIUM && (section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-model"), "client-bound-model") : Config.globalClientboundModel()); + + // 当模型值完成分配的时候 + customModelDataFuture.thenAccept(customModelData -> ResourceConfigUtils.runCatching(path, node, () -> { + + // item model + Key itemModel = null; + + // 如果这个版本可以使用 item model + if (!isVanillaItem && needsItemModelCompatibility()) { + // 如果用户主动设定了item model,那么肯定要设置 + if (section.containsKey("item-model")) { + itemModel = Key.from(section.get("item-model").toString()); + } + // 用户没设置item model也没设置custom model data,那么为他生成一个基于物品id的item model + else if (customModelData == 0) { + itemModel = id; + } + // 用户没设置item model但是有custom model data,那么就使用custom model data + } + + CustomItem.Builder itemBuilder = createPlatformItemBuilder(uniqueId, material, clientBoundMaterial); + if (customModelData > 0) { + if (clientBoundModel) itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData)); + else itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); + } + if (itemModel != null) { + if (clientBoundModel) itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModel)); + else itemBuilder.dataModifier(new ItemModelModifier<>(itemModel)); + } + + // 对于不重要的配置,可以仅警告,不返回 + ExceptionCollector collector = new ExceptionCollector<>(); + + // 应用物品数据 + try { + applyDataModifiers(MiscUtils.castToMap(section.get("data"), true), itemBuilder::dataModifier); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + } + + // 应用客户端侧数据 + try { + if (VersionHelper.PREMIUM) { + applyDataModifiers(MiscUtils.castToMap(section.get("client-bound-data"), true), itemBuilder::clientBoundDataModifier); + } + } catch (LocalizedResourceConfigException e) { + collector.add(e); + } + + // 如果不是原版物品,那么加入ce的标识符 + if (!isVanillaItem) + itemBuilder.dataModifier(new IdModifier<>(id)); + + // 事件 + Map>> eventTriggerListMap; + try { + eventTriggerListMap = EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + eventTriggerListMap = Map.of(); + } + + // 设置 + ItemSettings settings; + try { + settings = Optional.ofNullable(ResourceConfigUtils.get(section, "settings")) + .map(map -> ItemSettings.fromMap(MiscUtils.castToMap(map, true))) + .map(it -> isVanillaItem ? it.canPlaceRelatedVanillaBlock(true) : it) + .orElse(ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem)); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + settings = ItemSettings.of().canPlaceRelatedVanillaBlock(isVanillaItem); + } + + // 行为 + List behaviors; + try { + behaviors = ResourceConfigUtils.parseConfigAsList(ResourceConfigUtils.get(section, "behavior", "behaviors"), map -> ItemBehaviors.fromMap(pack, path, node, id, map)); + } catch (LocalizedResourceConfigException e) { + collector.add(e); + behaviors = Collections.emptyList(); + } + + // 如果有物品更新器 + if (section.containsKey("updater")) { + Map updater = ResourceConfigUtils.getAsMap(section.get("updater"), "updater"); + List versions = new ArrayList<>(2); + for (Map.Entry entry : updater.entrySet()) { + try { + int version = Integer.parseInt(entry.getKey()); + versions.add(new ItemUpdateConfig.Version( + version, + ResourceConfigUtils.parseConfigAsList(entry.getValue(), map -> ItemUpdaters.fromMap(id, map)).toArray(new ItemUpdater[0]) + )); + } catch (NumberFormatException ignored) { + } + } + ItemUpdateConfig config = new ItemUpdateConfig(versions); + itemBuilder.updater(config); + itemBuilder.dataModifier(new ItemVersionModifier<>(config.maxVersion())); + } + + // 构建自定义物品 + CustomItem customItem = itemBuilder + .isVanillaItem(isVanillaItem) + .behaviors(behaviors) + .settings(settings) + .events(eventTriggerListMap) + .build(); + + // 添加到缓存 + addCustomItem(customItem); + + // 如果有类别,则添加 + if (section.containsKey("category")) { + AbstractItemManager.this.plugin.itemBrowserManager().addExternalCategoryMember(id, MiscUtils.getAsStringList(section.get("category")).stream().map(Key::of).toList()); + } + + /* + * ======================== + * + * 模型配置分界线 + * + * ======================== + */ + + // 模型配置区域,如果这里被配置了,那么用户必须要配置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) { + collector.throwIfPresent(); + return; + } + + boolean needsModelSection = isModernFormatRequired() || (needsLegacyCompatibility() && legacyModelSection == null); + // 只对自定义物品有这个限制,既没有模型值也没有item-model + if (!isVanillaItem && customModelData == 0 && itemModel == null) { + collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model_id")); + } + + // 新版格式 + ItemModel modernModel = null; + // 旧版格式 + TreeSet legacyOverridesModels = null; + // 如果需要支持新版item model 或者用户需要旧版本兼容,但是没配置legacy-model + if (needsModelSection) { + // 1.21.4+必须要配置model区域,如果不需要高版本兼容,则可以只写legacy-model + if (modelSection == null) { + collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model")); + return; + } + try { + modernModel = ItemModels.fromMap(modelSection); + for (ModelGeneration generation : modernModel.modelsToGenerate()) { + prepareModelGeneration(generation); + } + } catch (LocalizedResourceConfigException e) { + collector.addAndThrow(e); + } + } + // 如果需要旧版本兼容 + if (needsLegacyCompatibility()) { + if (legacyModelSection != null) { + try { + LegacyItemModel legacyItemModel = LegacyItemModel.fromMap(legacyModelSection, customModelData); + for (ModelGeneration generation : legacyItemModel.modelsToGenerate()) { + prepareModelGeneration(generation); + } + legacyOverridesModels = new TreeSet<>(legacyItemModel.overrides()); + } catch (LocalizedResourceConfigException e) { + collector.addAndThrow(e); + } + } else { + legacyOverridesModels = new TreeSet<>(); + processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, clientBoundMaterial, customModelData); + if (legacyOverridesModels.isEmpty()) { + collector.add(new LocalizedResourceConfigException("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString())); + } + } + } + + // 自定义物品的model处理 + if (!isVanillaItem) { + // 这个item-model是否存在,且是原版item-model + boolean isVanillaItemModel = itemModel != null && AbstractPackManager.PRESET_ITEMS.containsKey(itemModel); + // 使用了自定义模型值 + if (customModelData != 0) { + // 如果用户主动设置了item-model且为原版物品,则使用item-model为基础模型,否则使用其视觉材质对应的item-model + Key finalBaseModel = isVanillaItemModel ? itemModel : clientBoundMaterial; + // 检查cmd冲突 + Map conflict = AbstractItemManager.this.cmdConflictChecker.computeIfAbsent(finalBaseModel, k -> new HashMap<>()); + if (conflict.containsKey(customModelData)) { + collector.addAndThrow(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) { + collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.item_model.conflict", itemModel.asString())); + } + + // 使用了item-model组件,且不是原版物品的 + if (itemModel != null && !isVanillaItemModel) { + if (isModernFormatRequired() && modernModel != null) { + AbstractItemManager.this.modernItemModels1_21_4.put(itemModel, 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(itemModel, 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") + )); + } + } + + // 抛出异常 + collector.throwIfPresent(); + + }, () -> GsonHelper.get().toJson(section))); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/EmptyItemBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/EmptyItemBehavior.java index 68c0c1e49..6546c56c3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/EmptyItemBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/EmptyItemBehavior.java @@ -13,7 +13,7 @@ public class EmptyItemBehavior extends ItemBehavior { public static class Factory implements ItemBehaviorFactory { @Override - public ItemBehavior create(Pack pack, Path path, Key id, Map arguments) { + public ItemBehavior create(Pack pack, Path path, String node, Key id, Map arguments) { return INSTANCE; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviorFactory.java b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviorFactory.java index 4b5ebe888..0f90c6223 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviorFactory.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/behavior/ItemBehaviorFactory.java @@ -8,5 +8,5 @@ import java.util.Map; public interface ItemBehaviorFactory { - ItemBehavior create(Pack pack, Path path, Key id, Map arguments); + ItemBehavior create(Pack pack, Path path, String node, Key id, Map arguments); } 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 6ab3f1d38..21399de3d 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 @@ -23,7 +23,7 @@ public class ItemBehaviors { .register(ResourceKey.create(Registries.ITEM_BEHAVIOR_FACTORY.location(), key), factory); } - public static ItemBehavior fromMap(Pack pack, Path path, Key id, Map map) { + public static ItemBehavior fromMap(Pack pack, Path path, String node, Key id, Map map) { if (map == null || map.isEmpty()) return EmptyItemBehavior.INSTANCE; String type = ResourceConfigUtils.requireNonEmptyStringOrThrow(map.get("type"), "warning.config.item.behavior.missing_type"); Key key = Key.withDefaultNamespace(type, Key.DEFAULT_NAMESPACE); @@ -31,25 +31,6 @@ public class ItemBehaviors { if (factory == null) { throw new LocalizedResourceConfigException("warning.config.item.behavior.invalid_type", type); } - return factory.create(pack, path, id, map); - } - - public static List fromList(Pack pack, Path path, Key id, List> list) { - List behaviors = new ArrayList<>(list.size()); - for (Map map : list) { - behaviors.add(fromMap(pack, path, id, map)); - } - return behaviors; - } - - @SuppressWarnings("unchecked") - public static List fromObj(Pack pack, Path path, Key id, Object behaviorObj) { - if (behaviorObj instanceof Map) { - return List.of(fromMap(pack, path, id, MiscUtils.castToMap(behaviorObj, false))); - } else if (behaviorObj instanceof List) { - return fromList(pack, path, id, (List>) behaviorObj); - } else { - return List.of(); - } + return factory.create(pack, path, node, id, map); } } \ No newline at end of file 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 c9db7e549..6a9fc4273 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 @@ -135,10 +135,10 @@ public abstract class AbstractRecipeManager implements RecipeManager { } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (!Config.enableRecipeSystem()) return; if (AbstractRecipeManager.this.byId.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.recipe.duplicate", path, id); + throw new LocalizedResourceConfigException("warning.config.recipe.duplicate"); } Recipe recipe = RecipeSerializers.fromMap(id, section); try { 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 eab304ce6..268e9bdc9 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 @@ -608,7 +608,6 @@ public abstract class AbstractPackManager implements PackManager { return cachedConfigs; } - // todo 本地化日志 private void loadResourceConfigs(Predicate predicate) { long o1 = System.nanoTime(); TreeMap> cachedConfigs = this.updateCachedConfigFiles(); @@ -622,13 +621,12 @@ public abstract class AbstractPackManager implements PackManager { switch (parser) { case SectionConfigParser configParser -> { for (CachedConfigSection cached : entry.getValue()) { - try { - configParser.parseSection(cached.pack(), cached.filePath(), cached.config()); - } catch (LocalizedException e) { - printWarningRecursively(e, cached.filePath(), cached.prefix()); - } catch (Exception e) { - this.plugin.logger().warn("Unexpected error loading file " + cached.filePath() + " - '" + parser.sectionId()[0] + "'. Please find the cause according to the stacktrace or seek developer help. Additional info: " + GsonHelper.get().toJson(cached.config()), e); - } + ResourceConfigUtils.runCatching( + cached.filePath(), + cached.prefix(), + () -> configParser.parseSection(cached.pack(), cached.filePath(), cached.config()), + () -> GsonHelper.get().toJson(cached.config()) + ); } } case IdObjectConfigParser configParser -> { @@ -636,13 +634,13 @@ public abstract class AbstractPackManager implements PackManager { for (Map.Entry configEntry : cached.config().entrySet()) { String key = configEntry.getKey(); Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); - try { - configParser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue()); - } catch (LocalizedException e) { - printWarningRecursively(e, cached.filePath(), cached.prefix() + "." + key); - } 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); - } + String node = cached.prefix() + "." + key; + ResourceConfigUtils.runCatching( + cached.filePath(), + node, + () -> configParser.parseObject(cached.pack(), cached.filePath(), node, id, configEntry.getValue()), + () -> GsonHelper.get().toJson(configEntry.getValue()) + ); } } } @@ -651,49 +649,37 @@ public abstract class AbstractPackManager implements PackManager { for (Map.Entry configEntry : cached.config().entrySet()) { String key = configEntry.getKey(); Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); - try { - if (configEntry.getValue() instanceof Map configSection0) { - Map config = castToMap(configSection0, false); - if ((boolean) config.getOrDefault("debug", false)) { - this.plugin.logger().info(GsonHelper.get().toJson(this.plugin.templateManager().applyTemplates(id, config))); - } - if ((boolean) config.getOrDefault("enable", true)) { - configParser.parseSection(cached.pack(), cached.filePath(), id, MiscUtils.castToMap(this.plugin.templateManager().applyTemplates(id, config), false)); - } - } else { - TranslationManager.instance().log("warning.config.structure.not_section", cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); - } - } catch (LocalizedException e) { - printWarningRecursively(e, cached.filePath(), cached.prefix() + "." + key); - } 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); + if (!(configEntry.getValue() instanceof Map section)) { + TranslationManager.instance().log("warning.config.structure.not_section", + cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); + continue; } + Map config = castToMap(section, false); + if ((boolean) config.getOrDefault("debug", false)) { + this.plugin.logger().info(GsonHelper.get().toJson(this.plugin.templateManager().applyTemplates(id, config))); + } + if (!(boolean) config.getOrDefault("enable", true)) { + continue; + } + String node = cached.prefix() + "." + key; + ResourceConfigUtils.runCatching( + cached.filePath(), + node, + () -> configParser.parseSection(cached.pack(), cached.filePath(), node, id, MiscUtils.castToMap(this.plugin.templateManager().applyTemplates(id, config), false)), + () -> GsonHelper.get().toJson(section) + ); } } } default -> { } } - 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"); } } - private void printWarningRecursively(LocalizedException e, Path path, String prefix) { - for (Throwable t : e.getSuppressed()) { - if (t instanceof LocalizedException suppressed) { - printWarningRecursively(suppressed, path, prefix); - } - } - if (e instanceof LocalizedResourceConfigException exception) { - exception.setPath(path); - exception.setId(prefix); - } - TranslationManager.instance().log(e.node(), e.arguments()); - } - private void processConfigEntry(Map.Entry entry, Path path, Pack pack, BiConsumer callback) { if (entry.getValue() instanceof Map typeSections0) { String key = entry.getKey(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoId.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoId.java deleted file mode 100644 index 15e4cf7fc..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/AutoId.java +++ /dev/null @@ -1,200 +0,0 @@ -package net.momirealms.craftengine.core.pack.cache; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import net.momirealms.craftengine.core.util.FileUtils; -import net.momirealms.craftengine.core.util.GsonHelper; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.function.Predicate; - -public class AutoId { - private final Path cachePath; - private final BiMap forcedIds = HashBiMap.create(128); - - private final Map cachedIds = new HashMap<>(); - private final BitSet occupiedIds = new BitSet(); - private final Map> autoIds = new HashMap<>(); - private int currentAutoId; - private int minId; - private int maxId; - - public AutoId(Path cachePath) { - this.cachePath = cachePath; - } - - public void reset(int startIndex, int endIndex) { - this.minId = startIndex; - this.currentAutoId = startIndex; - this.maxId = endIndex; - this.occupiedIds.clear(); - this.forcedIds.clear(); - this.autoIds.clear(); - this.cachedIds.clear(); - } - - public void arrangeForTheRest() { - // 然后处理自动分配的ID - for (Map.Entry> entry : this.autoIds.entrySet()) { - String name = entry.getKey(); - CompletableFuture future = entry.getValue(); - - // 不应该触发 - if (future.isDone()) { - continue; - } - - // 尝试使用缓存的ID,并且其有效 - Integer cachedId = this.cachedIds.get(name); - if (cachedId != null && !this.occupiedIds.get(cachedId) && cachedId >= this.minId && cachedId <= this.maxId) { - this.occupiedIds.set(cachedId); - future.complete(cachedId); - continue; - } - - // 寻找下一个可用的自动ID - int autoId = findNextAvailableAutoId(); - if (autoId == -1) { - // 没有可用的ID - future.completeExceptionally(new AutoIdExhaustedException(name, this.minId, this.maxId)); - continue; - } - - // 分配找到的ID - this.occupiedIds.set(autoId); - future.complete(autoId); - this.cachedIds.put(name, autoId); - } - - // 清空futureIds,因为所有请求都已处理 - this.autoIds.clear(); - } - - private int findNextAvailableAutoId() { - // 如果已经用尽 - if (this.currentAutoId > this.maxId) { - return -1; - } - // 寻找下一个可用的id - this.currentAutoId = this.occupiedIds.nextClearBit(this.currentAutoId); - // 已经用完了 - if (this.currentAutoId > maxId) { - return -1; - } - // 找到了 - return this.currentAutoId; - } - - // 强制使用某个id,这时候直接标记到occupiedIds,如果被占用,则直接抛出异常 - public CompletableFuture forceId(final String name, int index) { - // 检查ID是否在有效范围内,一般不会在这触发 - if (index < this.minId || index > this.maxId) { - return CompletableFuture.failedFuture(new AutoIdOutOfRangeException(name, index, this.minId, this.maxId)); - } - - // 检查ID是否已被其他名称占用 - String previous = this.forcedIds.inverse().get(index); - if (previous != null && !previous.equals(name)) { - return CompletableFuture.failedFuture(new AutoIdConflictException(previous, index)); - } - - this.forcedIds.put(name, index); - this.cachedIds.remove(name); // 如果曾经被缓存过,那么移除 - return CompletableFuture.completedFuture(index); - } - - // 自动分配id,优先使用缓存的值 - public CompletableFuture autoId(final String name) { - CompletableFuture future = new CompletableFuture<>(); - this.autoIds.put(name, future); - return future; - } - - // 大多数时候通过指令,移除那些已经不再被使用的id,使用完以后记得调用saveCache以保存更改 - public int clearUnusedIds(Predicate predicate) { - List toRemove = new ArrayList<>(); - for (String id : this.cachedIds.keySet()) { - if (predicate.test(id)) { - toRemove.add(id); - } - } - for (String id : toRemove) { - Integer removedId = this.cachedIds.remove(id); - if (removedId != null) { - // 只有当这个ID不是强制ID时才从occupiedIds中移除 - if (!forcedIds.containsValue(removedId)) { - occupiedIds.clear(removedId); - } - } - } - return toRemove.size(); - } - - // 获取已分配的ID(用于调试或查询) - public Integer getId(String name) { - if (forcedIds.containsKey(name)) { - return forcedIds.get(name); - } - return cachedIds.get(name); - } - - // 获取所有已分配的ID映射 - public Map getAllocatedIds() { - Map result = new HashMap<>(); - result.putAll(forcedIds); - result.putAll(cachedIds); - return Collections.unmodifiableMap(result); - } - - // 检查某个ID是否已被占用 - public boolean isIdOccupied(int id) { - return occupiedIds.get(id); - } - - // 从缓存中加载文件 - public void loadCache() throws IOException { - if (!Files.exists(this.cachePath)) { - return; - } - JsonElement element = GsonHelper.readJsonFile(this.cachePath); - if (element instanceof JsonObject jsonObject) { - for (Map.Entry entry : jsonObject.entrySet()) { - if (entry.getValue() instanceof JsonPrimitive primitive) { - int id = primitive.getAsInt(); - this.cachedIds.put(entry.getKey(), id); - } - } - } - } - - // 保存缓存到文件 - public void saveCache() throws IOException { - FileUtils.createDirectoriesSafe(this.cachePath.getParent()); - GsonHelper.writeJsonFile(GsonHelper.get().toJsonTree(this.cachedIds), this.cachePath); - } - - public static class AutoIdConflictException extends RuntimeException { - public AutoIdConflictException(String previousOwner, int id) { - super("ID " + id + " is already occupied by: " + previousOwner); - } - } - - public static class AutoIdOutOfRangeException extends RuntimeException { - public AutoIdOutOfRangeException(String name, int id, int min, int max) { - super("ID " + id + " for '" + name + "' is out of range. Valid range: " + min + "-" + max); - } - } - - public static class AutoIdExhaustedException extends RuntimeException { - public AutoIdExhaustedException(String name, int min, int max) { - super("No available auto ID for '" + name + "'. All IDs in range " + min + "-" + max + " are occupied."); - } - } -} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java new file mode 100644 index 000000000..9e6d44b2f --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java @@ -0,0 +1,226 @@ +package net.momirealms.craftengine.core.pack.cache; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import net.momirealms.craftengine.core.util.FileUtils; +import net.momirealms.craftengine.core.util.GsonHelper; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Predicate; + +public class IdAllocator { + private final Path cacheFilePath; + private final BiMap forcedIdMap = HashBiMap.create(128); + private final Map cachedIdMap = new HashMap<>(); + private final BitSet occupiedIdSet = new BitSet(); + private final Map> pendingAllocations = new HashMap<>(); + + private int nextAutoId; + private int minId; + private int maxId; + + public IdAllocator(Path cacheFilePath) { + this.cacheFilePath = cacheFilePath; + } + + /** + * 重置分配器状态 + * @param minId 最小ID(包含) + * @param maxId 最大ID(包含) + */ + public void reset(int minId, int maxId) { + this.minId = minId; + this.nextAutoId = minId; + this.maxId = maxId; + this.occupiedIdSet.clear(); + this.forcedIdMap.clear(); + this.pendingAllocations.clear(); + this.cachedIdMap.clear(); + } + + /** + * 处理所有待分配的自动ID请求 + */ + public void processPendingAllocations() { + for (Map.Entry> entry : this.pendingAllocations.entrySet()) { + String name = entry.getKey(); + CompletableFuture future = entry.getValue(); + + if (future.isDone()) { + continue; // 不应该发生的情况 + } + + // 优先尝试使用缓存的ID + Integer cachedId = this.cachedIdMap.get(name); + if (isIdAvailable(cachedId)) { + allocateId(name, cachedId, future); + continue; + } + + // 分配新的自动ID + int newId = findNextAvailableId(); + if (newId == -1) { + future.completeExceptionally(new IdExhaustedException(name, this.minId, this.maxId)); + continue; + } + + allocateId(name, newId, future); + this.cachedIdMap.put(name, newId); + } + + this.pendingAllocations.clear(); + } + + private boolean isIdAvailable(Integer id) { + return id != null && id >= this.minId && id <= this.maxId + && !this.occupiedIdSet.get(id); + } + + private void allocateId(String name, int id, CompletableFuture future) { + this.occupiedIdSet.set(id); + future.complete(id); + } + + private int findNextAvailableId() { + if (this.nextAutoId > this.maxId) { + return -1; + } + + this.nextAutoId = this.occupiedIdSet.nextClearBit(this.nextAutoId); + return this.nextAutoId <= this.maxId ? this.nextAutoId : -1; + } + + /** + * 强制分配指定ID,无视限制 + * @param name 名称 + * @param id 要分配的ID + * @return 分配结果的Future + */ + public CompletableFuture assignFixedId(String name, int id) { + // 检查ID是否被其他名称占用 + String existingOwner = this.forcedIdMap.inverse().get(id); + if (existingOwner != null && !existingOwner.equals(name)) { + return CompletableFuture.failedFuture(new IdConflictException(existingOwner, id)); + } + + this.forcedIdMap.put(name, id); + this.cachedIdMap.remove(name); // 清除可能的缓存 + this.occupiedIdSet.set(id); + return CompletableFuture.completedFuture(id); + } + + /** + * 请求自动分配ID + * @param name 名称 + * @return 分配结果的Future + */ + public CompletableFuture requestAutoId(String name) { + CompletableFuture future = new CompletableFuture<>(); + this.pendingAllocations.put(name, future); + return future; + } + + /** + * 清理不再使用的ID + * @param shouldRemove 判断是否应该移除的谓词 + * @return 被移除的ID数量 + */ + public int cleanupUnusedIds(Predicate shouldRemove) { + List idsToRemove = new ArrayList<>(); + for (String id : this.cachedIdMap.keySet()) { + if (shouldRemove.test(id)) { + idsToRemove.add(id); + } + } + + int removedCount = 0; + for (String id : idsToRemove) { + Integer removedId = this.cachedIdMap.remove(id); + if (removedId != null && !this.forcedIdMap.containsValue(removedId)) { + this.occupiedIdSet.clear(removedId); + removedCount++; + } + } + return removedCount; + } + + /** + * 获取指定名称的ID + * @param name 名称 + * @return ID,如果不存在返回null + */ + public Integer getId(String name) { + Integer forcedId = this.forcedIdMap.get(name); + return forcedId != null ? forcedId : this.cachedIdMap.get(name); + } + + /** + * 获取所有已分配的ID映射(不可修改) + */ + public Map getAllAllocatedIds() { + Map result = new HashMap<>(); + result.putAll(this.forcedIdMap); + result.putAll(this.cachedIdMap); + return Collections.unmodifiableMap(result); + } + + /** + * 检查ID是否已被占用 + */ + public boolean isIdOccupied(int id) { + return this.occupiedIdSet.get(id); + } + + /** + * 从文件加载缓存 + */ + public void loadFromCache() throws IOException { + if (!Files.exists(this.cacheFilePath)) { + return; + } + + JsonElement element = GsonHelper.readJsonFile(this.cacheFilePath); + if (element instanceof JsonObject jsonObject) { + for (Map.Entry entry : jsonObject.entrySet()) { + if (entry.getValue() instanceof JsonPrimitive primitive) { + int id = primitive.getAsInt(); + this.cachedIdMap.put(entry.getKey(), id); + } + } + } + } + + /** + * 保存缓存到文件 + */ + public void saveToCache() throws IOException { + FileUtils.createDirectoriesSafe(this.cacheFilePath.getParent()); + GsonHelper.writeJsonFile(GsonHelper.get().toJsonTree(this.cachedIdMap), this.cacheFilePath); + } + + // 异常类保持不变,但建议也重命名以保持一致性 + public static class IdConflictException extends RuntimeException { + public IdConflictException(String previousOwner, int id) { + super("ID " + id + " is already occupied by: " + previousOwner); + } + } + + public static class IdOutOfRangeException extends RuntimeException { + public IdOutOfRangeException(String name, int id, int min, int max) { + super("ID " + id + " for '" + name + "' is out of range. Valid range: " + min + "-" + max); + } + } + + public static class IdExhaustedException extends RuntimeException { + public IdExhaustedException(String name, int min, int max) { + super("No available auto ID for '" + name + "'. All IDs in range " + min + "-" + max + " are occupied."); + } + } +} \ No newline at end of file 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 c2da59fa2..1cb3d542b 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 @@ -159,6 +159,8 @@ public class Config { protected boolean item$update_triggers$click_in_inventory; protected boolean item$update_triggers$drop; protected boolean item$update_triggers$pick_up; + protected int item$custom_model_data_starting_value$default; + protected Map item$custom_model_data_starting_value$overrides; protected String equipment$sacrificed_vanilla_armor$type; protected Key equipment$sacrificed_vanilla_armor$asset_id; @@ -239,6 +241,7 @@ public class Config { .addIgnoredRoute(PluginProperties.getValue("config"), "resource-pack.delivery.hosting", '.') .addIgnoredRoute(PluginProperties.getValue("config"), "chunk-system.process-invalid-blocks.convert", '.') .addIgnoredRoute(PluginProperties.getValue("config"), "chunk-system.process-invalid-furniture.convert", '.') + .addIgnoredRoute(PluginProperties.getValue("config"), "item.custom-model-data-starting-value.overrides", '.') .build()); } try { @@ -398,6 +401,22 @@ public class Config { item$update_triggers$click_in_inventory = config.getBoolean("item.update-triggers.click-in-inventory", false); item$update_triggers$drop = config.getBoolean("item.update-triggers.drop", false); item$update_triggers$pick_up = config.getBoolean("item.update-triggers.pick-up", false); + item$custom_model_data_starting_value$default = config.getInt("item.custom-model-data-starting-value.default", 10000); + + Section customModelDataOverridesSection = config.getSection("item.custom-model-data-starting-value.overrides"); + if (customModelDataOverridesSection != null) { + Map customModelDataOverrides = new HashMap<>(); + for (Map.Entry entry : customModelDataOverridesSection.getStringRouteMappedValues(false).entrySet()) { + if (entry.getValue() instanceof String s) { + customModelDataOverrides.put(Key.of(entry.getKey()), Integer.parseInt(s)); + } else if (entry.getValue() instanceof Integer i) { + customModelDataOverrides.put(Key.of(entry.getKey()), i); + } + } + item$custom_model_data_starting_value$overrides = customModelDataOverrides; + } else { + item$custom_model_data_starting_value$overrides = Map.of(); + } // block block$sound_system$enable = config.getBoolean("block.sound-system.enable", true); @@ -752,6 +771,13 @@ public class Config { return instance.furniture$hide_base_entity; } + public static int customModelDataStartingValue(Key material) { + if (instance.item$custom_model_data_starting_value$overrides.containsKey(material)) { + return instance.item$custom_model_data_starting_value$overrides.get(material); + } + return instance.item$custom_model_data_starting_value$default; + } + public static int compressionMethod() { int id = instance.chunk_system$compression_method; if (id <= 0 || id > CompressionMethod.METHOD_COUNT) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java index 2b2eb5125..9238a31cc 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java @@ -8,6 +8,6 @@ import java.nio.file.Path; public interface IdObjectConfigParser extends ConfigParser { - default void parseObject(Pack pack, Path path, Key id, Object object) throws LocalizedException { + default void parseObject(Pack pack, Path path, String node, Key id, Object object) throws LocalizedException { } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java index b137ebfe6..e14e42ba2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java @@ -9,6 +9,6 @@ import java.util.Map; public interface IdSectionConfigParser extends ConfigParser { - default void parseSection(Pack pack, Path path, Key id, Map section) throws LocalizedException { + default void parseSection(Pack pack, Path path, String node, Key id, Map section) throws LocalizedException { } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java index 9d1a505aa..33c2622f4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -51,9 +51,9 @@ public class TemplateManagerImpl implements TemplateManager { } @Override - public void parseObject(Pack pack, Path path, Key id, Object obj) { + public void parseObject(Pack pack, Path path, String node, Key id, Object obj) { if (templates.containsKey(id)) { - throw new LocalizedResourceConfigException("warning.config.template.duplicate", path.toString(), id.toString()); + throw new LocalizedResourceConfigException("warning.config.template.duplicate"); } // 预处理会将 string类型的键或值解析为ArgumentString,以加速模板应用。所以处理后不可能存在String类型。 templates.put(id, preprocessUnknownValue(obj)); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java index d858deed2..ee677e725 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.config.IdObjectConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.Nullable; import java.nio.file.Path; @@ -49,7 +50,7 @@ public class GlobalVariableManager implements Manageable { } @Override - public void parseObject(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Object object) throws LocalizedException { + public void parseObject(Pack pack, Path path, String node, Key id, Object object) throws LocalizedException { if (object != null) { GlobalVariableManager.this.globalVariables.put(id.value(), object.toString()); } 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 7edb1900e..ed34e31a9 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 @@ -110,7 +110,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { String name = section.getOrDefault("name", id).toString(); List members = MiscUtils.getAsStringList(section.getOrDefault("list", List.of())); Key icon = Key.of(section.getOrDefault("icon", ItemKeys.STONE).toString()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/LocalizedResourceConfigException.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/LocalizedResourceConfigException.java index 994e4c785..5017b6012 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/LocalizedResourceConfigException.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/LocalizedResourceConfigException.java @@ -37,7 +37,7 @@ public class LocalizedResourceConfigException extends LocalizedException { super.setArgument(0, path.toString()); } - public void setId(String id) { + public void setNode(String id) { super.setArgument(1, id); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index f1e119a26..41b8bb69f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -257,10 +257,10 @@ public class TranslationManagerImpl implements TranslationManager { } @Override - public void parseSection(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, net.momirealms.craftengine.core.util.Key id, Map section) { Locale locale = TranslationManager.parseLocale(id.value()); if (locale == null) { - throw new LocalizedResourceConfigException("warning.config.i18n.unknown_locale", path, id); + throw new LocalizedResourceConfigException("warning.config.i18n.unknown_locale"); } Map bundle = new HashMap<>(); @@ -288,7 +288,7 @@ public class TranslationManagerImpl implements TranslationManager { } @Override - public void parseSection(Pack pack, Path path, net.momirealms.craftengine.core.util.Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, net.momirealms.craftengine.core.util.Key id, Map section) { String langId = id.value().toLowerCase(Locale.ENGLISH); Map sectionData = section.entrySet().stream() .collect(Collectors.toMap( 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 6ca57ab61..2e6def245 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 @@ -80,7 +80,7 @@ public abstract class AbstractSoundManager implements SoundManager { } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (AbstractSoundManager.this.songs.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.jukebox_song.duplicate"); } @@ -107,7 +107,7 @@ public abstract class AbstractSoundManager implements SoundManager { } @Override - public void parseSection(Pack pack, Path path, Key id, Map section) { + public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (AbstractSoundManager.this.byId.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.sound.duplicate"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index 58c09669e..b1a135387 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -1,13 +1,16 @@ package net.momirealms.craftengine.core.util; import com.mojang.datafixers.util.Either; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.world.Vec3d; import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; +import java.nio.file.Path; import java.util.*; import java.util.function.Function; import java.util.function.Supplier; @@ -280,4 +283,31 @@ public final class ResourceConfigUtils { } } } + + public static void runCatching(Path configPath, String node, Runnable runnable, Supplier config) { + try { + runnable.run(); + } catch (LocalizedException e) { + printWarningRecursively(e, configPath, node); + } catch (Exception e) { + String message = "Unexpected error loading file " + configPath + " - '" + node + "'."; + if (config != null) { + message += " Configuration details: " + config.get(); + } + CraftEngine.instance().logger().warn(message, e); + } + } + + private static void printWarningRecursively(LocalizedException e, Path path, String node) { + for (Throwable t : e.getSuppressed()) { + if (t instanceof LocalizedException suppressed) { + printWarningRecursively(suppressed, path, node); + } + } + if (e instanceof LocalizedResourceConfigException exception) { + exception.setPath(path); + exception.setNode(node); + } + TranslationManager.instance().log(e.node(), e.arguments()); + } } From 20382babbbc6b72ffb1db099e6f2b68cb276eb64 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 27 Sep 2025 18:59:00 +0800 Subject: [PATCH 071/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/pack/cache/IdAllocator.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java index 9e6d44b2f..da851ec1d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java @@ -49,19 +49,23 @@ public class IdAllocator { * 处理所有待分配的自动ID请求 */ public void processPendingAllocations() { + for (Map.Entry entry : this.cachedIdMap.entrySet()) { + CompletableFuture future = this.pendingAllocations.get(entry.getKey()); + if (future != null) { + int id = entry.getValue(); + if (!isIdAvailable(id)) { + continue; + } + allocateId(id, future); + } + } + for (Map.Entry> entry : this.pendingAllocations.entrySet()) { String name = entry.getKey(); CompletableFuture future = entry.getValue(); if (future.isDone()) { - continue; // 不应该发生的情况 - } - - // 优先尝试使用缓存的ID - Integer cachedId = this.cachedIdMap.get(name); - if (isIdAvailable(cachedId)) { - allocateId(name, cachedId, future); - continue; + continue; // 已经在前面分配过了 } // 分配新的自动ID @@ -71,7 +75,7 @@ public class IdAllocator { continue; } - allocateId(name, newId, future); + allocateId(newId, future); this.cachedIdMap.put(name, newId); } @@ -83,7 +87,7 @@ public class IdAllocator { && !this.occupiedIdSet.get(id); } - private void allocateId(String name, int id, CompletableFuture future) { + private void allocateId(int id, CompletableFuture future) { this.occupiedIdSet.set(id); future.complete(id); } From 4a9f7cacde85b7f2cb7ce270bdf79d0092ec6e61 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 27 Sep 2025 19:18:30 +0800 Subject: [PATCH 072/125] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=BD=BD=E5=85=A5?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/pack/cache/IdAllocator.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java index da851ec1d..63913d3e5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java @@ -20,7 +20,7 @@ public class IdAllocator { private final BiMap forcedIdMap = HashBiMap.create(128); private final Map cachedIdMap = new HashMap<>(); private final BitSet occupiedIdSet = new BitSet(); - private final Map> pendingAllocations = new HashMap<>(); + private final Map> pendingAllocations = new LinkedHashMap<>(); private int nextAutoId; private int minId; @@ -206,10 +206,22 @@ public class IdAllocator { */ public void saveToCache() throws IOException { FileUtils.createDirectoriesSafe(this.cacheFilePath.getParent()); - GsonHelper.writeJsonFile(GsonHelper.get().toJsonTree(this.cachedIdMap), this.cacheFilePath); + + // 创建按ID排序的TreeMap + Map sortedById = new TreeMap<>(); + for (Map.Entry entry : this.cachedIdMap.entrySet()) { + sortedById.put(entry.getValue(), entry.getKey()); + } + + // 创建有序的JSON对象 + JsonObject sortedJsonObject = new JsonObject(); + for (Map.Entry entry : sortedById.entrySet()) { + sortedJsonObject.addProperty(entry.getValue(), entry.getKey()); + } + + GsonHelper.writeJsonFile(sortedJsonObject, this.cacheFilePath); } - // 异常类保持不变,但建议也重命名以保持一致性 public static class IdConflictException extends RuntimeException { public IdConflictException(String previousOwner, int id) { super("ID " + id + " is already occupied by: " + previousOwner); From 6bd2ed2ef217d1bcebcc1040eeeae8a43a2f1983 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 27 Sep 2025 19:51:52 +0800 Subject: [PATCH 073/125] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E5=80=BC=E8=87=AA=E5=8A=A8=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/en.yml | 1 + .../core/item/AbstractItemManager.java | 119 +++++++++--------- .../core/pack/cache/IdAllocator.java | 34 ++++- 3 files changed, 90 insertions(+), 64 deletions(-) diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 8bfe8c7ad..eaf5c8740 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -193,6 +193,7 @@ warning.config.item.invalid_custom_model_data: "Issue found in file 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.custom_model_data_exhausted: "Issue found in file - Cannot allocate custom model data for item '' as the custom model data has already been exhausted." warning.config.item.invalid_component: "Issue found in file - The item '' is using a non-existing component type ''." warning.config.item.missing_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." warning.config.item.missing_model: "Issue found in file - The item '' is missing the required 'model' section for 1.21.4+ resource pack support." 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 b31c26ff3..0dee19193 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 @@ -52,7 +52,6 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected final Map> customItemsById = new HashMap<>(); protected final Map> customItemsByPath = new HashMap<>(); 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<>(); @@ -128,7 +127,6 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl this.modernOverrides.clear(); this.customItemTags.clear(); this.equipments.clear(); - this.cmdConflictChecker.clear(); this.modernItemModels1_21_4.clear(); this.modernItemModels1_21_2.clear(); } @@ -331,7 +329,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } private boolean needsItemModelCompatibility() { - return Config.packMaxVersion().isAbove(MinecraftVersions.V1_21_2); + return Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2); } public Map idAllocators() { @@ -425,11 +423,19 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl customModelDataFuture = CompletableFuture.completedFuture(0); } - // 是否使用客户端侧模型 - boolean clientBoundModel = VersionHelper.PREMIUM && (section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-model"), "client-bound-model") : Config.globalClientboundModel()); - // 当模型值完成分配的时候 - customModelDataFuture.thenAccept(customModelData -> ResourceConfigUtils.runCatching(path, node, () -> { + customModelDataFuture.whenComplete((customModelData, throwable) -> ResourceConfigUtils.runCatching(path, node, () -> { + + if (throwable != null) { + // 检测custom model data 冲突 + if (throwable instanceof IdAllocator.IdConflictException exception) { + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(exception.id()), exception.previousOwner()); + } + // custom model data 已被用尽,不太可能 + else if (throwable instanceof IdAllocator.IdExhaustedException) { + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_exhausted"); + } + } // item model Key itemModel = null; @@ -447,6 +453,9 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 用户没设置item model但是有custom model data,那么就使用custom model data } + // 是否使用客户端侧模型 + boolean clientBoundModel = VersionHelper.PREMIUM && (section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-model"), "client-bound-model") : Config.globalClientboundModel()); + CustomItem.Builder itemBuilder = createPlatformItemBuilder(uniqueId, material, clientBoundMaterial); if (customModelData > 0) { if (clientBoundModel) itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData)); @@ -553,6 +562,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl * ======================== */ + // 原版物品还改模型?自己替换json去 + if (isVanillaItem) { + return; + } + // 模型配置区域,如果这里被配置了,那么用户必须要配置custom-model-data或item-model Map modelSection = MiscUtils.castToMap(section.get("model"), true); Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); @@ -561,9 +575,8 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return; } - boolean needsModelSection = isModernFormatRequired() || (needsLegacyCompatibility() && legacyModelSection == null); // 只对自定义物品有这个限制,既没有模型值也没有item-model - if (!isVanillaItem && customModelData == 0 && itemModel == null) { + if (customModelData == 0 && itemModel == null) { collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model_id")); } @@ -572,7 +585,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // 旧版格式 TreeSet legacyOverridesModels = null; // 如果需要支持新版item model 或者用户需要旧版本兼容,但是没配置legacy-model - if (needsModelSection) { + if (isModernFormatRequired() || (needsLegacyCompatibility() && legacyModelSection == null)) { // 1.21.4+必须要配置model区域,如果不需要高版本兼容,则可以只写legacy-model if (modelSection == null) { collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.missing_model")); @@ -603,66 +616,52 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl legacyOverridesModels = new TreeSet<>(); processModelRecursively(modernModel, new LinkedHashMap<>(), legacyOverridesModels, clientBoundMaterial, customModelData); if (legacyOverridesModels.isEmpty()) { - collector.add(new LocalizedResourceConfigException("warning.config.item.legacy_model.cannot_convert", path.toString(), id.asString())); + collector.add(new LocalizedResourceConfigException("warning.config.item.legacy_model.cannot_convert")); } } } - // 自定义物品的model处理 - if (!isVanillaItem) { - // 这个item-model是否存在,且是原版item-model - boolean isVanillaItemModel = itemModel != null && AbstractPackManager.PRESET_ITEMS.containsKey(itemModel); - // 使用了自定义模型值 - if (customModelData != 0) { - // 如果用户主动设置了item-model且为原版物品,则使用item-model为基础模型,否则使用其视觉材质对应的item-model - Key finalBaseModel = isVanillaItemModel ? itemModel : clientBoundMaterial; - // 检查cmd冲突 - Map conflict = AbstractItemManager.this.cmdConflictChecker.computeIfAbsent(finalBaseModel, k -> new HashMap<>()); - if (conflict.containsKey(customModelData)) { - collector.addAndThrow(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) { - collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.item_model.conflict", itemModel.asString())); - } + boolean hasLegacyModel = legacyOverridesModels != null && !legacyOverridesModels.isEmpty(); + boolean hasModernModel = modernModel != null; - // 使用了item-model组件,且不是原版物品的 - if (itemModel != null && !isVanillaItemModel) { - if (isModernFormatRequired() && modernModel != null) { - AbstractItemManager.this.modernItemModels1_21_4.put(itemModel, 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(itemModel, k -> new TreeSet<>()); - lom.addAll(legacyOverridesModels); - } - } - } else { - // 原版物品的item model覆写 - if (isModernFormatRequired()) { - AbstractItemManager.this.modernItemModels1_21_4.put(id, new ModernItemModel( + // 自定义物品的model处理 + // 这个item-model是否存在,且是原版item-model + boolean isVanillaItemModel = itemModel != null && AbstractPackManager.PRESET_ITEMS.containsKey(itemModel); + // 使用了自定义模型值 + if (customModelData != 0) { + // 如果用户主动设置了item-model且为原版物品,则使用item-model为基础模型,否则使用其视觉材质对应的item-model + Key finalBaseModel = isVanillaItemModel ? itemModel : clientBoundMaterial; + // 添加新版item model + if (isModernFormatRequired() && hasModernModel) { + 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() && hasLegacyModel) { + TreeSet lom = AbstractItemManager.this.legacyOverrides.computeIfAbsent(finalBaseModel, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); + } + } else if (isVanillaItemModel) { + collector.addAndThrow(new LocalizedResourceConfigException("warning.config.item.item_model.conflict", itemModel.asString())); + } + + // 使用了item-model组件,且不是原版物品的 + if (itemModel != null && !isVanillaItemModel) { + if (isModernFormatRequired() && hasModernModel) { + AbstractItemManager.this.modernItemModels1_21_4.put(itemModel, 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 (needsItemModelCompatibility() && needsLegacyCompatibility() && hasLegacyModel) { + TreeSet lom = AbstractItemManager.this.modernItemModels1_21_2.computeIfAbsent(itemModel, k -> new TreeSet<>()); + lom.addAll(legacyOverridesModels); + } } // 抛出异常 diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java index 63913d3e5..a4fe866f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java @@ -223,20 +223,46 @@ public class IdAllocator { } public static class IdConflictException extends RuntimeException { + private final String previousOwner; + private final int id; + public IdConflictException(String previousOwner, int id) { super("ID " + id + " is already occupied by: " + previousOwner); + this.previousOwner = previousOwner; + this.id = id; } - } - public static class IdOutOfRangeException extends RuntimeException { - public IdOutOfRangeException(String name, int id, int min, int max) { - super("ID " + id + " for '" + name + "' is out of range. Valid range: " + min + "-" + max); + public String previousOwner() { + return previousOwner; + } + + public int id() { + return id; } } public static class IdExhaustedException extends RuntimeException { + private final String name; + private final int min; + private final int max; + public IdExhaustedException(String name, int min, int max) { super("No available auto ID for '" + name + "'. All IDs in range " + min + "-" + max + " are occupied."); + this.name = name; + this.min = min; + this.max = max; + } + + public String name() { + return name; + } + + public int min() { + return min; + } + + public int max() { + return max; } } } \ No newline at end of file From 32b678de4ba45ee31fa596656743e10072b9663e Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sun, 28 Sep 2025 04:18:05 +0800 Subject: [PATCH 074/125] =?UTF-8?q?=E5=86=85=E9=83=A8id=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E7=BB=91=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 47 ++- .../bukkit/block/BukkitCustomBlock.java | 128 +------ .../item/behavior/BlockItemBehavior.java | 17 +- .../behavior/DoubleHighBlockItemBehavior.java | 10 +- .../item/behavior/WallBlockItemBehavior.java | 7 +- .../DebugAppearanceStateUsageCommand.java | 16 - .../feature/DebugRealStateUsageCommand.java | 16 - .../resources/internal/configuration/gui.yml | 13 + .../src/main/resources/translations/de.yml | 7 +- .../src/main/resources/translations/en.yml | 12 +- .../src/main/resources/translations/es.yml | 7 +- .../src/main/resources/translations/ru_ru.yml | 7 +- .../src/main/resources/translations/tr.yml | 7 +- .../src/main/resources/translations/zh_cn.yml | 9 +- .../core/block/AbstractBlockManager.java | 341 +++++++++++++----- .../core/block/AbstractCustomBlock.java | 90 +---- .../craftengine/core/block/BlockSounds.java | 1 - .../core/block/BlockStateHolder.java | 8 +- .../core/block/BlockStateVariant.java | 25 -- .../core/block/BlockStateVariantProvider.java | 30 +- .../craftengine/core/block/CustomBlock.java | 19 - .../craftengine/core/block/EmptyBlock.java | 28 +- .../core/block/ImmutableBlockState.java | 4 +- .../core/block/InactiveCustomBlock.java | 6 +- .../core/block/parser/BlockNbtParser.java | 17 +- .../core/item/AbstractItemManager.java | 19 +- .../core/item/behavior/ItemBehaviors.java | 3 - .../core/pack/PendingConfigSection.java | 9 + .../core/pack/cache/IdAllocator.java | 27 +- .../craftengine/core/registry/Holder.java | 3 +- .../core/util/ResourceConfigUtils.java | 7 + .../DefaultSectionSerializer.java | 2 +- 32 files changed, 480 insertions(+), 462 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/PendingConfigSection.java 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 5fc635efe..413fc8cb3 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 @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.block; import com.google.common.collect.ImmutableList; -import it.unimi.dsi.fastutil.ints.IntArrayList; +import net.momirealms.craftengine.bukkit.block.behavior.UnsafeCompositeBlockBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BlockGenerator; @@ -16,15 +16,18 @@ import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.RegistryUtils; import net.momirealms.craftengine.bukkit.util.TagUtils; import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; +import net.momirealms.craftengine.core.block.behavior.BlockBehaviors; import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; import net.momirealms.craftengine.core.block.parser.BlockStateParser; +import net.momirealms.craftengine.core.loot.LootTable; 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.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.plugin.logger.Debugger; -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.sound.SoundData; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; @@ -61,7 +64,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { super(plugin, RegistryUtils.currentBlockRegistrySize(), Config.serverSideBlocks()); this.plugin = plugin; this.registerServerSideCustomBlocks(Config.serverSideBlocks()); - this.registerEmptyBlock(); + EmptyBlock.initialize(); instance = this; } @@ -114,6 +117,21 @@ public final class BukkitBlockManager extends AbstractBlockManager { super.delayedLoad(); } + @Override + public BlockBehavior createBlockBehavior(CustomBlock customBlock, List> behaviorConfig) { + if (behaviorConfig == null || behaviorConfig.isEmpty()) { + return new EmptyBlockBehavior(); + } else if (behaviorConfig.size() == 1) { + return BlockBehaviors.fromMap(customBlock, behaviorConfig.getFirst()); + } else { + List behaviors = new ArrayList<>(); + for (Map config : behaviorConfig) { + behaviors.add((AbstractBlockBehavior) BlockBehaviors.fromMap(customBlock, config)); + } + return new UnsafeCompositeBlockBehavior(customBlock, behaviors); + } + } + @Override protected void resendTags() { // if there's no change @@ -258,17 +276,6 @@ public final class BukkitBlockManager extends AbstractBlockManager { BlockRegistryMirror.init(states, new BukkitBlockStateWrapper(MBlocks.STONE$defaultState, BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState))); } - private void registerEmptyBlock() { - 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); - } - - @Override - protected CustomBlock.Builder platformBuilder(Key id) { - return BukkitCustomBlock.builder(id); - } - // 注册服务端侧的真实方块 private void registerServerSideCustomBlocks(int count) { // 这个会影响全局调色盘 @@ -379,6 +386,14 @@ public final class BukkitBlockManager extends AbstractBlockManager { return this.vanillaBlockStateCount; } + @Override + protected CustomBlock createCustomBlock(@NotNull Holder.Reference holder, + @NotNull BlockStateVariantProvider variantProvider, + @NotNull Map>> events, + @Nullable LootTable lootTable) { + return new BukkitCustomBlock(holder, variantProvider, events, lootTable); + } + public boolean isOpenableBlockSoundRemoved(Object blockOwner) { return false; } 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 b831a0cde..360e121ad 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 @@ -1,139 +1,27 @@ package net.momirealms.craftengine.bukkit.block; -import net.momirealms.craftengine.bukkit.block.behavior.UnsafeCompositeBlockBehavior; -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.reflection.minecraft.MFluids; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; -import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.bukkit.util.KeyUtils; -import net.momirealms.craftengine.bukkit.util.SoundUtils; -import net.momirealms.craftengine.core.block.*; -import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.BlockBehaviors; -import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; -import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.block.AbstractCustomBlock; +import net.momirealms.craftengine.core.block.BlockStateVariantProvider; +import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.loot.LootTable; -import net.momirealms.craftengine.core.plugin.CraftEngine; 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.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.registry.WritableRegistry; -import net.momirealms.craftengine.core.util.*; -import org.bukkit.Bukkit; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.*; +import java.util.List; +import java.util.Map; public final class BukkitCustomBlock extends AbstractCustomBlock { - private BukkitCustomBlock( - @NotNull Key id, + public BukkitCustomBlock( @NotNull Holder.Reference holder, - @NotNull Map> properties, - @NotNull Map appearances, - @NotNull Map variantMapper, - @NotNull BlockSettings settings, + @NotNull BlockStateVariantProvider variantProvider, @NotNull Map>> events, - @Nullable List> behavior, @Nullable LootTable lootTable ) { - super(id, holder, properties, appearances, variantMapper, settings, events, behavior, lootTable); - } - - @Override - protected BlockBehavior setupBehavior(List> behaviorConfig) { - if (behaviorConfig == null || behaviorConfig.isEmpty()) { - return new EmptyBlockBehavior(); - } else if (behaviorConfig.size() == 1) { - return BlockBehaviors.fromMap(this, behaviorConfig.getFirst()); - } else { - List behaviors = new ArrayList<>(); - for (Map config : behaviorConfig) { - behaviors.add((AbstractBlockBehavior) BlockBehaviors.fromMap(this, config)); - } - return new UnsafeCompositeBlockBehavior(this, behaviors); - } - } - - @SuppressWarnings("unchecked") - @Nullable - @Override - public LootTable lootTable() { - return (LootTable) super.lootTable(); - } - - public static Builder builder(Key id) { - return new BuilderImpl(id); - } - - public static class BuilderImpl implements Builder { - protected final Key id; - protected Map> properties; - protected Map appearances; - protected Map variantMapper; - protected BlockSettings settings; - protected List> behavior; - protected LootTable lootTable; - protected Map>> events; - - public BuilderImpl(Key id) { - this.id = id; - } - - @Override - public Builder events(Map>> events) { - this.events = events; - return this; - } - - @Override - public Builder appearances(Map appearances) { - this.appearances = appearances; - return this; - } - - @Override - public Builder behavior(List> behavior) { - this.behavior = behavior; - return this; - } - - @Override - public Builder lootTable(LootTable lootTable) { - this.lootTable = lootTable; - return this; - } - - @Override - public Builder properties(Map> properties) { - this.properties = properties; - return this; - } - - @Override - public Builder settings(BlockSettings settings) { - this.settings = settings; - return this; - } - - @Override - public Builder variantMapper(Map variantMapper) { - this.variantMapper = variantMapper; - return this; - } - - @Override - public @NotNull CustomBlock build() { - // create or get block holder - 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); - } + super(holder, variantProvider, events, lootTable); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java index a71c46f64..f8cb7dfcb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/BlockItemBehavior.java @@ -23,6 +23,7 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.context.ContextHolder; @@ -232,6 +233,15 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { return this.blockId; } + static void addPendingSection(Pack pack, Path path, String node, Key key, Map map) { + if (map.containsKey(key.toString())) { + // 防呆 + BukkitBlockManager.instance().blockParser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false))); + } else { + BukkitBlockManager.instance().blockParser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, MiscUtils.castToMap(map, false))); + } + } + public static class Factory implements ItemBehaviorFactory { @Override public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { @@ -240,12 +250,7 @@ public class BlockItemBehavior extends BlockBoundItemBehavior { throw new LocalizedResourceConfigException("warning.config.item.behavior.block.missing_block", new IllegalArgumentException("Missing required parameter 'block' for block_item behavior")); } if (id instanceof Map map) { - if (map.containsKey(key.toString())) { - // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); - } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); - } + addPendingSection(pack, path, node, key, map); return new BlockItemBehavior(key); } else { return new BlockItemBehavior(Key.of(id.toString())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java index 403d8eea3..7ad5a1bed 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java @@ -9,6 +9,7 @@ import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; @@ -43,15 +44,10 @@ public class DoubleHighBlockItemBehavior extends BlockItemBehavior { public ItemBehavior create(Pack pack, Path path, String node, Key key, Map arguments) { Object id = arguments.get("block"); if (id == null) { - throw new LocalizedResourceConfigException("warning.config.item.behavior.double_high.missing_block", new IllegalArgumentException("Missing required parameter 'block' for double_high_block_item behavior")); + throw new LocalizedResourceConfigException("warning.config.item.behavior.double_high.missing_block"); } if (id instanceof Map map) { - if (map.containsKey(key.toString())) { - // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); - } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); - } + addPendingSection(pack, path, node, key, map); return new DoubleHighBlockItemBehavior(key); } else { return new DoubleHighBlockItemBehavior(Key.of(id.toString())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java index 8f8232d4f..6e46af6cd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java @@ -41,12 +41,7 @@ public class WallBlockItemBehavior extends BlockItemBehavior { throw new LocalizedResourceConfigException("warning.config.item.behavior.wall_block.missing_block", new IllegalArgumentException("Missing required parameter 'block' for wall_block_item behavior")); } if (id instanceof Map map) { - if (map.containsKey(key.toString())) { - // 防呆 - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); - } else { - BukkitBlockManager.instance().blockParser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); - } + addPendingSection(pack, path, node, key, map); return new WallBlockItemBehavior(key); } else { return new WallBlockItemBehavior(Key.of(id.toString())); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java index ce6029653..2192b12d4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java @@ -1,26 +1,10 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.HoverEvent; -import net.kyori.adventure.text.format.NamedTextColor; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import net.momirealms.craftengine.core.util.Key; import org.bukkit.command.CommandSender; -import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; -import org.incendo.cloud.context.CommandContext; -import org.incendo.cloud.context.CommandInput; -import org.incendo.cloud.parser.standard.StringParser; -import org.incendo.cloud.suggestion.Suggestion; -import org.incendo.cloud.suggestion.SuggestionProvider; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; public class DebugAppearanceStateUsageCommand extends BukkitCommandFeature { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java index 04b7d0ce2..d30863b8c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java @@ -1,26 +1,10 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.event.HoverEvent; -import net.kyori.adventure.text.format.NamedTextColor; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import net.momirealms.craftengine.core.util.Key; import org.bukkit.command.CommandSender; -import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; -import org.incendo.cloud.context.CommandContext; -import org.incendo.cloud.context.CommandInput; -import org.incendo.cloud.parser.standard.StringParser; -import org.incendo.cloud.suggestion.Suggestion; -import org.incendo.cloud.suggestion.SuggestionProvider; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.CompletableFuture; public class DebugRealStateUsageCommand extends BukkitCommandFeature { diff --git a/common-files/src/main/resources/resources/internal/configuration/gui.yml b/common-files/src/main/resources/resources/internal/configuration/gui.yml index 42c53dee6..344d37d55 100644 --- a/common-files/src/main/resources/resources/internal/configuration/gui.yml +++ b/common-files/src/main/resources/resources/internal/configuration/gui.yml @@ -74,6 +74,7 @@ images: templates: internal:icon/2d: material: arrow + custom-model-data: ${model_data} data: item-name: ${name} lore: ${lore} @@ -92,6 +93,7 @@ items: internal:next_page_0: template: internal:icon/2d arguments: + model_data: 1000 texture: next_page_0 name: <#FAFAD2> lore: @@ -99,6 +101,7 @@ items: internal:next_page_1: template: internal:icon/2d arguments: + model_data: 1001 texture: next_page_1 name: <#808080> lore: @@ -106,6 +109,7 @@ items: internal:previous_page_0: template: internal:icon/2d arguments: + model_data: 1002 texture: previous_page_0 name: <#FAFAD2> lore: @@ -113,6 +117,7 @@ items: internal:previous_page_1: template: internal:icon/2d arguments: + model_data: 1003 texture: previous_page_1 name: <#808080> lore: @@ -120,29 +125,34 @@ items: internal:return: template: internal:icon/2d arguments: + model_data: 1004 texture: return name: <#DAA520> lore: null internal:next_recipe_0: material: arrow + custom-model-data: 1000 data: item-name: <#FAFAD2> lore: - <#F5F5F5>/ internal:next_recipe_1: material: arrow + custom-model-data: 1001 data: item-name: <#808080> lore: - <#696969>/ internal:previous_recipe_0: material: arrow + custom-model-data: 1002 data: item-name: <#FAFAD2> lore: - <#F5F5F5>/ internal:previous_recipe_1: material: arrow + custom-model-data: 1003 data: item-name: <#808080> lore: @@ -150,6 +160,7 @@ items: internal:get_item: template: internal:icon/2d arguments: + model_data: 1005 texture: get_item name: <#DAA520> lore: @@ -158,6 +169,7 @@ items: internal:cooking_info: template: internal:icon/2d arguments: + model_data: 1006 texture: cooking_info name: <#FF8C00> lore: @@ -166,6 +178,7 @@ items: internal:exit: template: internal:icon/2d arguments: + model_data: 1007 texture: exit name: <#DAA520> lore: null \ No newline at end of file diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 4e28bf879..1513a684b 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -184,7 +184,7 @@ warning.config.item.invalid_material: "Problem in Datei gefunden warning.config.item.invalid_custom_model_data: "Problem in Datei gefunden - Das Item '' verwendet eine negative Custom-Model-Data '', was ungültig ist." warning.config.item.bad_custom_model_data: "Problem in Datei gefunden - Das Item '' verwendet eine Custom-Model-Data '', die zu groß ist. Es wird empfohlen, einen Wert unter 16.777.216 zu verwenden." warning.config.item.item_model.conflict: "Problem in Datei gefunden - Das Item '' verwendet eine ungültige 'item-model'-Option, da dieses Item-Model bereits von einem Vanilla-Item belegt ist." -warning.config.item.custom_model_data_conflict: "Problem in Datei gefunden - Das Item '' verwendet eine Custom-Model-Data '', die bereits von Item '' belegt ist." +warning.config.item.custom_model_data.conflict: "Problem in Datei gefunden - Das Item '' verwendet eine Custom-Model-Data '', die bereits von Item '' belegt ist." warning.config.item.invalid_component: "Problem in Datei gefunden - Das Item '' verwendet einen nicht existierenden Component-Typ ''." warning.config.item.missing_model_id: "Problem in Datei gefunden - Beim Item '' fehlt das erforderliche 'custom-model-data'- oder 'item-model'-Argument." warning.config.item.missing_model: "Problem in Datei gefunden - Beim Item '' fehlt der erforderliche 'model'-Abschnitt für die Unterstützung von Resource Packs ab 1.21.4+." @@ -252,18 +252,15 @@ warning.config.block.state.property.missing_type: "Problem in Datei Problem in Datei gefunden - Der Block '' verwendet das ungültige Typ-Argument '' für die Property ''." warning.config.block.state.property.integer.invalid_range: "Problem in Datei gefunden - Der Block '' verwendet das ungültige 'range'-Argument '' für die Integer-Property ''. Korrekte Syntax: 1~2." warning.config.block.state.property.invalid_format: "Problem in Datei gefunden - Der Block '' verwendet ein ungültiges Block-State-Property-Format ''." -warning.config.block.state.missing_real_id: "Problem in Datei gefunden - Beim Block '' fehlt das erforderliche 'id'-Argument für 'state'. 'id' ist die serverseitige Block-ID, die für jeden Block-State-Typ eindeutig ist. Wenn du einen serverseitigen Block mit 'note_block' und ID 30 erstellst, wäre die echte Block-ID 'craftengine:note_block_30'." warning.config.block.state.missing_state: "Problem in Datei gefunden - Beim Block '' fehlt das erforderliche 'state'-Argument für 'state'." warning.config.block.state.missing_properties: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'properties'-Abschnitt für 'states'." warning.config.block.state.missing_appearances: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'appearances'-Abschnitt für 'states'." warning.config.block.state.missing_variants: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'variants'-Abschnitt für 'states'." -warning.config.block.state.variant.missing_appearance: "Problem in Datei gefunden - Beim Block '' fehlt das erforderliche 'appearance'-Argument für die Variante ''." warning.config.block.state.variant.invalid_appearance: "Problem in Datei gefunden - Der Block '' hat einen Fehler, dass die Variante '' eine nicht existierende Appearance '' verwendet." warning.config.block.state.invalid_vanilla: "Problem in Datei gefunden - Der Block '' verwendet einen ungültigen Vanilla-Block-State ''." warning.config.block.state.unavailable_vanilla: "Problem in Datei gefunden - Der Block '' verwendet einen nicht verfügbaren Vanilla-Block-State ''. Bitte gib diesen State in der mappings.yml frei." warning.config.block.state.invalid_vanilla_id: "Problem in Datei gefunden - Der Block '' verwendet einen Vanilla-Block-State '', der den verfügbaren Slot-Bereich '0~' überschreitet." -warning.config.block.state.conflict: "Problem in Datei gefunden - Der Block '' verwendet einen Vanilla-Block-State '', der bereits von '' belegt ist." -warning.config.block.state.bind_failed: "Problem in Datei gefunden - Der Block '' konnte den echten Block-State für '' nicht binden, da der State bereits von '' belegt ist." +warning.config.block.state.id.conflict: "Problem in Datei gefunden - Der Block '' konnte den echten Block-State für '' nicht binden, da der State bereits von '' belegt ist." warning.config.block.state.model.missing_path: "Problem in Datei gefunden - Beim Block '' fehlt die erforderliche 'path'-Option für 'model'." warning.config.block.state.model.invalid_path: "Problem in Datei gefunden - Der Block '' hat ein 'path'-Argument '', das ungültige Zeichen enthält. Bitte lies https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.block.state.model.conflict: "Problem in Datei gefunden - Der Block '' versucht, das Model '' an den Block-State '' zu binden, der bereits an das Model '' gebunden ist." diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index eaf5c8740..652e823a8 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -192,8 +192,8 @@ warning.config.item.invalid_material: "Issue found in file - The 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.custom_model_data_exhausted: "Issue found in file - Cannot allocate custom model data for item '' as the custom model data has already been exhausted." +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.custom_model_data.exhausted: "Issue found in file - Cannot allocate custom model data for item '' as the custom model data has already been exhausted." warning.config.item.invalid_component: "Issue found in file - The item '' is using a non-existing component type ''." warning.config.item.missing_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." warning.config.item.missing_model: "Issue found in file - The item '' is missing the required 'model' section for 1.21.4+ resource pack support." @@ -264,7 +264,6 @@ warning.config.block.state.property.missing_type: "Issue found in file < warning.config.block.state.property.invalid_type: "Issue found in file - The block '' is using the invalid type argument '' for property ''." warning.config.block.state.property.integer.invalid_range: "Issue found in file - The block '' is using the invalid 'range' argument '' for integer property ''. Correct syntax: 1~2." warning.config.block.state.property.invalid_format: "Issue found in file - The block '' is using an invalid block state property format ''." -warning.config.block.state.missing_real_id: "Issue found in file - The block '' is missing the required 'id' argument for 'state'. 'id' is the serverside block id which is unique for each type of block state. If you create a serverside side block with 'note_block' and id 30, then the real block id would be 'craftengine:note_block_30'." warning.config.block.state.missing_state: "Issue found in file - The block '' is missing the required 'state' argument for 'state'." warning.config.block.state.missing_properties: "Issue found in file - The block '' is missing the required 'properties' section for 'states'." warning.config.block.state.missing_appearances: "Issue found in file - The block '' is missing the required 'appearances' section for 'states'." @@ -274,14 +273,13 @@ warning.config.block.state.entity_renderer.item_display.missing_item: "I warning.config.block.state.entity_renderer.text_display.missing_text: "Issue found in file - The block '' is missing the required 'text' argument for 'text_display' entity renderer." warning.config.block.state.entity_renderer.better_model.missing_model: "Issue found in file - The block '' is missing the required 'model' argument for 'better_model' entity renderer." warning.config.block.state.entity_renderer.model_engine.missing_model: "Issue found in file - The block '' is missing the required 'model' argument for 'model_engine' entity renderer." -warning.config.block.state.variant.missing_appearance: "Issue found in file - The block '' is missing the required 'appearance' argument for variant ''." warning.config.block.state.variant.invalid_appearance: "Issue found in file - The block '' has an error that the variant '' is using a non-existing appearance ''." warning.config.block.state.invalid_vanilla: "Issue found in file - The block '' is using an invalid vanilla block state ''." warning.config.block.state.unavailable_vanilla: "Issue found in file - The block '' is using an unavailable vanilla block state ''. Please free that state in mappings.yml." warning.config.block.state.invalid_vanilla_id: "Issue found in file - The block '' is using a vanilla block state '' that exceeds the available slot range '0~'." -warning.config.block.state.conflict: "Issue found in file - The block '' is using a vanilla block state '' that has been occupied by ''." -warning.config.block.state.bind_failed: "Issue found in file - The block '' failed to bind real block state '' for '' as the state has been occupied by ''." -warning.config.block.state.invalid_real_id: "Issue found in file - The block '' is using a real block state '' that exceeds the available slot range '0~'. Consider adding more serverside blocks in 'config.yml' if the slots are used up." +warning.config.block.state.invalid_id: "Issue found in file - The block state ID range () used by block '' is outside the valid range of 0 to . Please add more server-side blocks in 'config.yml' if the current slots are exhausted." +warning.config.block.state.id.conflict: "Issue found in file - The block '' failed to bind real block state '' for '' as the state has been occupied by ''." +warning.config.block.state.id.exhausted: "Issue found in file - Cannot allocate enough real block state for block ''. Please add more server-side blocks in 'config.yml' and restart if the current slots are exhausted." warning.config.block.state.model.missing_path: "Issue found in file - The block '' is missing the required 'path' option for 'model'." warning.config.block.state.model.invalid_path: "Issue found in file - The block '' has a 'path' argument '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.block.state.model.conflict: "Issue found in file - The block '' is trying to bind model '' to block state '' which has already been bound to model ''" diff --git a/common-files/src/main/resources/translations/es.yml b/common-files/src/main/resources/translations/es.yml index 0429bbb86..d65bc899a 100644 --- a/common-files/src/main/resources/translations/es.yml +++ b/common-files/src/main/resources/translations/es.yml @@ -121,7 +121,7 @@ warning.config.item.settings.unknown: "Problema encontrado en el archivo warning.config.item.missing_material: "Problema encontrado en el archivo - El objeto '' carece del argumento requerido 'material'." warning.config.item.invalid_material: "Problema encontrado en el archivo - El objeto '' está usando un tipo de material inválido ''." warning.config.item.bad_custom_model_data: "Problema encontrado en el archivo - El objeto '' está usando un dato de modelo personalizado demasiado grande ''. Se recomienda usar un valor menor a 16.777.216." -warning.config.item.custom_model_data_conflict: "Problema encontrado en el archivo - El objeto '' está usando un dato de modelo personalizado '' que está ocupado por el objeto ''." +warning.config.item.custom_model_data.conflict: "Problema encontrado en el archivo - El objeto '' está usando un dato de modelo personalizado '' que está ocupado por el objeto ''." warning.config.item.missing_model_id: "Problema encontrado en el archivo - El objeto '' carece del argumento requerido 'custom-model-data' o 'item-model'." warning.config.item.behavior.missing_type: "Problema encontrado en el archivo - El objeto '' carece del argumento requerido 'type' para el comportamiento del objeto." warning.config.item.behavior.invalid_type: "Problema encontrado en el archivo - El objeto '' está usando un tipo de comportamiento de objeto inválido ''." @@ -175,18 +175,15 @@ warning.config.block.state.property.missing_type: "Problema encontrado e warning.config.block.state.property.invalid_type: "Problema encontrado en el archivo - El bloque '' está usando un argumento 'type' inválido '' para la propiedad ''." warning.config.block.state.property.integer.invalid_range: "Problema encontrado en el archivo - El bloque '' está usando un argumento 'range' inválido '' para la propiedad entero ''. Sintaxis correcta: 1~2." warning.config.block.state.property.invalid_format: "Problema encontrado en el archivo - El bloque '' está usando un formato de propiedad de estado de bloque inválido ''." -warning.config.block.state.missing_real_id: "Problema encontrado en el archivo - El bloque '' carece del argumento requerido 'id' para 'state'. 'id' es el id de bloque del lado del servidor que es único para cada tipo de estado de bloque. Si creas un bloque del lado del servidor con 'note_block' e id 30, el id de bloque real será 'craftengine:note_block_30'." warning.config.block.state.missing_state: "Problema encontrado en el archivo - El bloque '' carece del argumento requerido 'state' para 'state'." warning.config.block.state.missing_properties: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'properties' para 'states'." warning.config.block.state.missing_appearances: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'appearances' para 'states'." warning.config.block.state.missing_variants: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'variants' para 'states'." -warning.config.block.state.variant.missing_appearance: "Problema encontrado en el archivo - El bloque '' carece del argumento requerido 'appearance' para la variante ''." warning.config.block.state.variant.invalid_appearance: "Problema encontrado en el archivo - Hay un error en el bloque '' donde la variante '' está usando una apariencia inexistente ''." warning.config.block.state.invalid_vanilla: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla inválido ''." warning.config.block.state.unavailable_vanilla: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla no disponible ''. Por favor libera este estado en el archivo mappings.yml." warning.config.block.state.invalid_vanilla_id: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla '' que excede el rango de slots disponible '0~'." -warning.config.block.state.conflict: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla '' que está ocupado por ''." -warning.config.block.state.bind_failed: "Problema encontrado en el archivo - El bloque '' falló al vincular el estado de bloque real para '' porque está ocupado por el estado ''." +warning.config.block.state.id.conflict: "Problema encontrado en el archivo - El bloque '' falló al vincular el estado de bloque real para '' porque está ocupado por el estado ''." warning.config.block.state.model.missing_path: "Problema encontrado en el archivo - El bloque '' carece de la opción requerida 'path' para 'model'." warning.config.block.state.model.invalid_path: "Problema encontrado en el archivo - El bloque '' tiene un argumento 'path' '' que contiene caracteres prohibidos. Por favor lee https://minecraft.wiki/w/Resource_location#Legal_characters" warning.config.block.settings.unknown: "Problema encontrado en el archivo - El bloque '' está usando un tipo de configuración desconocido ''." diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml index dcb624e7a..be8170d1a 100644 --- a/common-files/src/main/resources/translations/ru_ru.yml +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -161,7 +161,7 @@ warning.config.item.missing_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.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+." @@ -225,18 +225,15 @@ warning.config.block.state.property.missing_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.id.conflict: "Проблема найдена в файле - Блоку '' не удалось привязать реальное состояние блока для '', так как состояние занято ''." 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: "Проблема найдена в файле - Блок '' использует неизвестный тип настройки ''." diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index e5b79c186..d283b67c1 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -120,7 +120,7 @@ warning.config.item.settings.unknown: " dosyasında sorun bulundu warning.config.item.missing_material: " dosyasında sorun bulundu - '' eşyası gerekli 'material' argümanı eksik." warning.config.item.invalid_material: " dosyasında sorun bulundu - '' eşyası geçersiz bir malzeme türü '' kullanıyor." warning.config.item.bad_custom_model_data: " dosyasında sorun bulundu - '' eşyası çok büyük bir özel model verisi '' kullanıyor. 16.777.216'dan düşük bir değer kullanmanız önerilir." -warning.config.item.custom_model_data_conflict: " dosyasında sorun bulundu - '' eşyası, '' eşyası tarafından işgal edilmiş bir özel model verisi '' kullanıyor." +warning.config.item.custom_model_data.conflict: " dosyasında sorun bulundu - '' eşyası, '' eşyası tarafından işgal edilmiş bir özel model verisi '' kullanıyor." warning.config.item.missing_model_id: " dosyasında sorun bulundu - '' eşyası gerekli 'custom-model-data' veya 'item-model' argümanı eksik." warning.config.item.behavior.missing_type: " dosyasında sorun bulundu - '' eşyası, eşya davranışı için gerekli 'type' argümanı eksik." warning.config.item.behavior.invalid_type: " dosyasında sorun bulundu - '' eşyası geçersiz bir eşya davranış türü '' kullanıyor." @@ -173,18 +173,15 @@ warning.config.block.state.property.missing_type: " dosyasında s warning.config.block.state.property.invalid_type: " dosyasında sorun bulundu - '' bloğu, '' özelliği için geçersiz bir 'type' argümanı '' kullanıyor." warning.config.block.state.property.integer.invalid_range: " dosyasında sorun bulundu - '' bloğu, '' tamsayı özelliği için geçersiz bir 'range' argümanı '' kullanıyor. Doğru sözdizimi: 1~2." warning.config.block.state.property.invalid_format: " dosyasında sorun bulundu - '' bloğu, geçersiz bir blok durum özelliği formatı '' kullanıyor." -warning.config.block.state.missing_real_id: " dosyasında sorun bulundu - '' bloğu, 'state' için gerekli 'id' argümanı eksik. 'id', her blok durumu türü için benzersiz olan sunucu tarafı blok kimliğidir. 'note_block' ve id 30 ile bir sunucu tarafı blok oluşturursanız, gerçek blok kimliği 'craftengine:note_block_30' olur." warning.config.block.state.missing_state: " dosyasında sorun bulundu - '' bloğu, 'state' için gerekli 'state' argümanı eksik." warning.config.block.state.missing_properties: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'properties' bölümü eksik." warning.config.block.state.missing_appearances: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'appearances' bölümü eksik." warning.config.block.state.missing_variants: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'variants' bölümü eksik." -warning.config.block.state.variant.missing_appearance: " dosyasında sorun bulundu - '' bloğu, '' varyantı için gerekli 'appearance' argümanı eksik." warning.config.block.state.variant.invalid_appearance: " dosyasında sorun bulundu - '' bloğunda, '' varyantının var olmayan bir görünüm '' kullandığı bir hata var." warning.config.block.state.invalid_vanilla: " dosyasında sorun bulundu - '' bloğu geçersiz bir vanilya blok durumu '' kullanıyor." warning.config.block.state.unavailable_vanilla: " dosyasında sorun bulundu - '' bloğu kullanılamayan bir vanilya blok durumu '' kullanıyor. Lütfen bu durumu mappings.yml dosyasında serbest bırakın." warning.config.block.state.invalid_vanilla_id: " dosyasında sorun bulundu - '' bloğu, mevcut yuva aralığı '0~' aşan bir vanilya blok durumu '' kullanıyor." -warning.config.block.state.conflict: " dosyasında sorun bulundu - '' bloğu, '' tarafından işgal edilmiş bir vanilya blok durumu '' kullanıyor." -warning.config.block.state.bind_failed: " dosyasında sorun bulundu - '' bloğu, durum '' tarafından işgal edildiği için '' için gerçek blok durumu bağlamada başarısız oldu." +warning.config.block.state.id.conflict: " dosyasında sorun bulundu - '' bloğu, durum '' tarafından işgal edildiği için '' için gerçek blok durumu bağlamada başarısız oldu." warning.config.block.state.model.missing_path: " dosyasında sorun bulundu - '' bloğu, 'model' için gerekli 'path' seçeneği eksik." warning.config.block.state.model.invalid_path: " dosyasında sorun bulundu - '' bloğunun, yasak karakterler içeren bir 'path' argümanı '' var. Lütfen https://minecraft.wiki/w/Resource_location#Legal_characters sayfasını okuyun." warning.config.block.settings.unknown: " dosyasında sorun bulundu - '' bloğu bilinmeyen bir ayar türü '' kullanıyor." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 56720fb27..04bea5c58 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -192,7 +192,7 @@ 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.item_model.conflict: "在文件 发现问题 - 物品 '' 使用了无效的 'item-model' 选项. 这个 item-model 已经存在对应的原版物品" -warning.config.item.custom_model_data_conflict: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 已被物品 '' 占用" +warning.config.item.custom_model_data.conflict: "在文件 发现问题 - 物品 '' 使用的自定义模型数据 '' 已被物品 '' 占用" warning.config.item.invalid_component: "在文件 发现问题 - 物品 '' 使用了未知的数据组件 ''" warning.config.item.missing_model_id: "在文件 发现问题 - 物品 '' 缺少必需的 'custom-model-data' 或 'item-model' 参数" warning.config.item.missing_model: "在文件 中发现问题 - 物品 '' 缺少支持 1.21.4+ 资源包必需的 'model' 配置项" @@ -260,19 +260,16 @@ warning.config.block.state.property.missing_type: "在文件 发 warning.config.block.state.property.invalid_type: "在文件 发现问题 - 方块 '' 的属性 '' 使用了无效的类型参数 ''" warning.config.block.state.property.integer.invalid_range: "在文件 发现问题 - 方块 '' 的整数属性 '' 使用了无效的范围参数 '' 正确语法: 1~2" warning.config.block.state.property.invalid_format: "在文件 发现问题 - 方块 '' 使用了无效的方块状态属性格式 ''" -warning.config.block.state.missing_real_id: "在文件 发现问题 - 方块 '' 的 'state' 缺少必需的 'id' 参数 该 ID 是服务端方块 ID 用于唯一标识每种方块状态类型" warning.config.block.state.missing_state: "在文件 发现问题 - 方块 '' 的 'state' 缺少必需的 'state' 参数" warning.config.block.state.missing_properties: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'properties' 段落" warning.config.block.state.missing_appearances: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'appearances' 段落" warning.config.block.state.missing_variants: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'variants' 段落" -warning.config.block.state.variant.missing_appearance: "在文件 发现问题 - 方块 '' 的变体 '' 缺少必需的 'appearance' 参数" warning.config.block.state.variant.invalid_appearance: "在文件 发现问题 - 方块 '' 的变体 '' 使用了不存在的 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.invalid_real_id: "在文件 发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~' 如果槽位已用尽 请在 config.yml 中添加更多服务端侧方块" +warning.config.block.state.id.conflict: "在文件 发现问题 - 方块 '' 无法为 '' 绑定真实方块状态 '' 因该状态已被 '' 占用" +warning.config.block.state.invalid_id: "在文件 发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~' 如果槽位已用尽 请在 config.yml 中添加更多服务端侧方块" warning.config.block.state.model.missing_path: "在文件 发现问题 - 方块 '' 的 'model' 缺少必需的 'path' 选项" warning.config.block.state.model.invalid_path: "在文件 发现问题 - 方块 '' 的 'path' 参数 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" warning.config.block.state.model.conflict: "在文件 发现问题 - 方块 '' 正尝试将模型 '' 绑定到方块状态 '' 上, 但是此状态已绑定了另一个模型 ''" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 9cb662404..bd39b0a59 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -1,32 +1,54 @@ package net.momirealms.craftengine.core.block; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Maps; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; +import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfigs; +import net.momirealms.craftengine.core.block.parser.BlockNbtParser; import net.momirealms.craftengine.core.block.properties.Properties; import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.item.AbstractItemManager; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.pack.ResourceLocation; +import net.momirealms.craftengine.core.pack.cache.IdAllocator; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.*; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; +import net.momirealms.craftengine.core.plugin.config.SectionConfigParser; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.plugin.logger.Debugger; +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 net.momirealms.sparrow.nbt.CompoundTag; import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.IOException; import java.nio.file.Path; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.function.Predicate; public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager { @@ -50,6 +72,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final Map soundReplacements = new HashMap<>(512, 0.5f); // 用于note_block:0这样格式的自动分配 protected final Map> blockStateArranger = new HashMap<>(); + // 根据registry id找note_block:x中的x值 + protected final Map reversedBlockStateArranger = new HashMap<>(); // 全方块状态映射文件,用于网络包映射 protected final int[] blockStateMappings; // 原版方块状态数量 @@ -103,6 +127,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.byId.clear(); this.soundReplacements.clear(); this.blockStateArranger.clear(); + this.reversedBlockStateArranger.clear(); this.appearanceToRealState.clear(); Arrays.fill(this.blockStateMappings, -1); Arrays.fill(this.immutableBlockStates, EmptyBlock.STATE); @@ -125,20 +150,12 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Optional.ofNullable(this.byId.get(id)); } - protected void addBlockInternal(Key id, CustomBlock customBlock) { - ExceptionCollector exceptionCollector = new ExceptionCollector<>(); + protected void addBlockInternal(CustomBlock customBlock) { // 绑定外观状态等 for (ImmutableBlockState state : customBlock.variantProvider().states()) { int internalId = state.customBlockState().registryId(); int appearanceId = state.vanillaBlockState().registryId(); int index = internalId - this.vanillaBlockStateCount; - ImmutableBlockState previous = this.immutableBlockStates[index]; - // todo 应当提前判断位置 - if (previous != null && !previous.isEmpty()) { - exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.bind_failed", - state.toString(), previous.toString(), getBlockOwnerId(previous.customBlockState()).toString())); - continue; - } this.immutableBlockStates[index] = state; this.blockStateMappings[internalId] = appearanceId; this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId); @@ -147,8 +164,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.modBlockStateOverrides.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(appearanceId)); } } - this.byId.put(id, customBlock); - exceptionCollector.throwIfPresent(); + this.byId.put(customBlock.id(), customBlock); } @Override @@ -210,17 +226,22 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Optional.ofNullable(this.appearanceToRealState.get(appearanceStateId)).orElse(List.of()); } + public abstract BlockBehavior createBlockBehavior(CustomBlock customBlock, List> behaviorConfig); + protected abstract void resendTags(); protected abstract boolean isVanillaBlock(Key id); protected abstract Key getBlockOwnerId(int id); - protected abstract CustomBlock.Builder platformBuilder(Key id); - protected abstract void setVanillaBlockTags(Key id, List tags); - public abstract int vanillaBlockStateCount(); + protected abstract int vanillaBlockStateCount(); + + protected abstract CustomBlock createCustomBlock(@NotNull Holder.Reference holder, + @NotNull BlockStateVariantProvider variantProvider, + @NotNull Map>> events, + @Nullable LootTable lootTable); public class BlockStateMappingParser implements SectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"block-state-mappings", "block-state-mapping"}; @@ -261,7 +282,9 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem continue; } AbstractBlockManager.this.blockStateMappings[beforeState.registryId()] = afterState.registryId(); - AbstractBlockManager.this.blockStateArranger.computeIfAbsent(getBlockOwnerId(beforeState), k -> new ArrayList<>()).add(afterState); + List blockStateWrappers = AbstractBlockManager.this.blockStateArranger.computeIfAbsent(getBlockOwnerId(beforeState), k -> new ArrayList<>()); + blockStateWrappers.add(beforeState); + AbstractBlockManager.this.reversedBlockStateArranger.put(beforeState.registryId(), blockStateWrappers.size() - 1); } exceptionCollector.throwIfPresent(); } @@ -269,6 +292,63 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem public class BlockParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; + private final IdAllocator internalIdAllocator; + private final Map appearanceIdAllocators = new HashMap<>(); + private final List pendingConfigSections = new ArrayList<>(); + + public BlockParser() { + this.internalIdAllocator = new IdAllocator(AbstractBlockManager.this.plugin.dataFolderPath().resolve("cache").resolve("custom-block-states.json")); + } + + public void addPendingConfigSection(PendingConfigSection section) { + this.pendingConfigSections.add(section); + } + + @Override + public void postProcess() { + this.internalIdAllocator.processPendingAllocations(); + try { + this.internalIdAllocator.saveToCache(); + } catch (IOException e) { + AbstractBlockManager.this.plugin.logger().warn("Error while saving custom block state allocation", e); + } + } + + @Override + public void preProcess() { + this.internalIdAllocator.reset(0, Config.serverSideBlocks() - 1); + try { + this.internalIdAllocator.loadFromCache(); + } catch (IOException e) { + AbstractBlockManager.this.plugin.logger().warn("Error while loading custom block state allocation cache", e); + } + for (PendingConfigSection section : this.pendingConfigSections) { + ResourceConfigUtils.runCatching( + section.path(), + section.node(), + () -> parseSection(section.pack(), section.path(), section.node(), section.id(), section.config()), + () -> GsonHelper.get().toJson(section.config()) + ); + } + this.pendingConfigSections.clear(); + } + + @Nullable + public IdAllocator getOrCreateAppearanceIdAllocator(Key type) { + if (!AbstractBlockManager.this.blockStateArranger.containsKey(type)) { + return null; + } + return this.appearanceIdAllocators.computeIfAbsent(type, k -> { + IdAllocator newAllocator = new IdAllocator(plugin.dataFolderPath().resolve("cache").resolve("visual-block-states").resolve(k.value() + ".json")); + newAllocator.reset(0, AbstractBlockManager.this.blockStateArranger.get(type).size()); + try { + newAllocator.loadFromCache(); + } catch (IOException e) { + AbstractBlockManager.this.plugin.logger().warn("Error while loading visual block states cache for block " + k.asString(), e); + } + return newAllocator; + }); + } @Override public String[] sectionId() { @@ -289,7 +369,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem if (AbstractBlockManager.this.byId.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.block.duplicate"); } - parseCustomBlock(id, section); + parseCustomBlock(path, node, id, section); } } @@ -304,86 +384,171 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } - private void parseCustomBlock(Key id, Map section) { - // 获取方块设置 + private void parseCustomBlock(Path path, String node, Key id, Map section) { + // 获取共享方块设置 BlockSettings settings = BlockSettings.fromMap(id, MiscUtils.castToMap(section.get("settings"), true)); - // 读取基础外观配置 - Map> properties; - Map appearances; - Map variants; // 读取states区域 - Map stateSection = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow( - ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"), true); + Map stateSection = MiscUtils.castToMap(ResourceConfigUtils.requireNonNullOrThrow(ResourceConfigUtils.get(section, "state", "states"), "warning.config.block.missing_state"), true); boolean singleState = !stateSection.containsKey("properties"); - // 单方块状态 - if (singleState) { - int internalId = ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("id"), "warning.config.block.state.missing_real_id"), "id"); - // 获取原版外观的注册表id - BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(stateSection.get("state"), "warning.config.block.state.missing_state")); - Optional[]> blockEntityRenderer = parseBlockEntityRender(stateSection.get("entity-renderer")); - // 为原版外观赋予外观模型并检查模型冲突 - this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(stateSection, "model", "models")); - // 设置参数 - properties = Map.of(); - appearances = Map.of("", new BlockStateAppearance(appearanceState, blockEntityRenderer)); - variants = Map.of("", new BlockStateVariant("", settings, getInternalBlockState(internalId))); - } - // 多方块状态 - else { - properties = parseBlockProperties(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), "properties")); - appearances = parseBlockAppearances(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances")); - variants = parseBlockVariants( - ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), "variants"), - appearances::containsKey, settings - ); - } + // 读取方块的property,通过property决定 + Map> properties = singleState ? Map.of() : parseBlockProperties(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), "properties")); + // 注册方块容器 + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).getOrRegisterForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), id)); - addBlockInternal(id, platformBuilder(id) - .appearances(appearances) - .variantMapper(variants) - .properties(properties) - .settings(settings) - .lootTable(LootTable.fromMap(ResourceConfigUtils.getAsMapOrNull(section.get("loot"), "loot"))) - .behavior(MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))) - .events(EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event"))) - .build()); - } + // 根据properties生成variant provider + BlockStateVariantProvider variantProvider = new BlockStateVariantProvider(holder, (owner, propertyMap) -> { + ImmutableBlockState blockState = new ImmutableBlockState(owner, propertyMap); + blockState.setSettings(settings); + return blockState; + }, properties); - private Map parseBlockVariants(Map variantsSection, - Predicate appearanceValidator, - BlockSettings parentSettings) { - Map variants = new HashMap<>(); - for (Map.Entry entry : variantsSection.entrySet()) { - Map variantSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); - String variantNBT = entry.getKey(); - String appearance = ResourceConfigUtils.requireNonEmptyStringOrThrow(variantSection.get("appearance"), "warning.config.block.state.variant.missing_appearance"); - if (!appearanceValidator.test(appearance)) { - throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearance); + ImmutableList states = variantProvider.states(); + List> internalIdAllocators = new ArrayList<>(states.size()); + + // 如果用户指定了起始id + if (stateSection.containsKey("id")) { + int startingId = ResourceConfigUtils.getAsInt(stateSection.get("id"), "id"); + int endingId = startingId + states.size() - 1; + if (startingId < 0 || endingId >= Config.serverSideBlocks()) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_id", startingId + "~" + endingId, String.valueOf(Config.serverSideBlocks() - 1)); + } + // 先检测范围冲突 + List> conflicts = this.internalIdAllocator.getFixedIdsBetween(startingId, endingId); + if (!conflicts.isEmpty()) { + ExceptionCollector exceptionCollector = new ExceptionCollector<>(); + for (Pair conflict : conflicts) { + int internalId = conflict.right(); + int index = internalId - startingId; + exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.id.conflict", states.get(index).toString(), conflict.left(), BlockManager.createCustomBlockKey(internalId).toString())); + } + exceptionCollector.throwIfPresent(); + } + // 强行分配id + for (ImmutableBlockState blockState : states) { + String blockStateId = blockState.toString(); + internalIdAllocators.add(this.internalIdAllocator.assignFixedId(blockStateId, startingId++)); + } + } + // 未指定,则使用自动分配 + else { + for (ImmutableBlockState blockState : states) { + String blockStateId = blockState.toString(); + internalIdAllocators.add(this.internalIdAllocator.requestAutoId(blockStateId)); } - BlockStateWrapper internalBlockState = getInternalBlockState(ResourceConfigUtils.getAsInt(ResourceConfigUtils.requireNonNullOrThrow(variantSection.get("id"), "warning.config.block.state.missing_real_id"), "id")); - Map anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings"); - variants.put(variantNBT, new BlockStateVariant(appearance, anotherSetting == null ? parentSettings : BlockSettings.ofFullCopy(parentSettings, anotherSetting), internalBlockState)); } - return variants; - } - private BlockStateWrapper getInternalBlockState(int internalId) { - if (internalId >= Config.serverSideBlocks()) { - throw new LocalizedResourceConfigException("warning.config.block.state.invalid_real_id", BlockManager.createCustomBlockKey(internalId).asString(), String.valueOf(Config.serverSideBlocks() - 1)); - } - return BlockRegistryMirror.byId(internalId + vanillaBlockStateCount()); - } + CompletableFutures.allOf(internalIdAllocators).thenRun(() -> ResourceConfigUtils.runCatching(path, node, () -> { + for (int i = 0; i < internalIdAllocators.size(); i++) { + CompletableFuture future = internalIdAllocators.get(i); + try { + int internalId = future.get(); + states.get(i).setCustomBlockState(BlockRegistryMirror.byId(internalId + AbstractBlockManager.this.vanillaBlockStateCount)); + } catch (ExecutionException e) { + Throwable cause = e.getCause(); + // 这里不会有conflict了,因为之前已经判断过了 + if (cause instanceof IdAllocator.IdExhaustedException) { + throw new LocalizedResourceConfigException("warning.config.block.state.id.exhausted"); + } else { + Debugger.BLOCK.warn(() -> "Unknown error while allocating internal block state id.", cause); + return; + } + } catch (InterruptedException e) { + AbstractBlockManager.this.plugin.logger().warn("Interrupted while parsing allocating internal block state", e); + return; + } + } - private Map parseBlockAppearances(Map appearancesSection) { - Map appearances = new HashMap<>(); - for (Map.Entry entry : appearancesSection.entrySet()) { - Map appearanceSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); - BlockStateWrapper appearanceId = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow( - appearanceSection.get("state"), "warning.config.block.state.missing_state")); - this.arrangeModelForStateAndVerify(appearanceId, ResourceConfigUtils.get(appearanceSection, "model", "models")); - appearances.put(entry.getKey(), new BlockStateAppearance(appearanceId, parseBlockEntityRender(appearanceSection.get("entity-renderer")))); - } - return appearances; + // 创建自定义方块 + AbstractCustomBlock customBlock = (AbstractCustomBlock) createCustomBlock( + holder, + variantProvider, + EventFunctions.parseEvents(ResourceConfigUtils.get(section, "events", "event")), + LootTable.fromMap(ResourceConfigUtils.getAsMapOrNull(section.get("loot"), "loot")) + ); + BlockBehavior blockBehavior = createBlockBehavior(customBlock, MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))); + customBlock.setBehavior(blockBehavior); + holder.bindValue(customBlock); + + // 单状态 + if (singleState) { + BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(stateSection.get("state"), "warning.config.block.state.missing_state")); + this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(stateSection, "model", "models")); + ImmutableBlockState onlyState = states.getFirst(); + // 为唯一的状态绑定外观 + onlyState.setVanillaBlockState(appearanceState); + parseBlockEntityRender(stateSection.get("entity-renderer")).ifPresent(onlyState::setConstantRenderers); + } else { + BlockStateWrapper anyAppearanceState = null; + Map appearancesSection = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances"); + // 也不能为空 + if (appearancesSection.isEmpty()) { + throw new LocalizedResourceConfigException("warning.config.block.state.missing_appearances"); + } + Map appearances = Maps.newHashMap(); + // 先解析所有的外观 + for (Map.Entry entry : appearancesSection.entrySet()) { + Map appearanceSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); + // 解析对应的视觉方块 + BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(appearanceSection.get("state"), "warning.config.block.state.missing_state")); + this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(appearanceSection, "model", "models")); + appearances.put(entry.getKey(), new BlockStateAppearance(appearanceState, parseBlockEntityRender(appearanceSection.get("entity-renderer")))); + if (anyAppearanceState == null) { + anyAppearanceState = appearanceState; + } + } + // 解析变体 + Map variantsSection = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), "variants"); + for (Map.Entry entry : variantsSection.entrySet()) { + Map variantSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); + String variantNBT = entry.getKey(); + // 先解析nbt,找到需要修改的方块状态 + CompoundTag tag = BlockNbtParser.deserialize(variantProvider, variantNBT); + if (tag == null) { + throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", variantNBT); + } + List possibleStates = variantProvider.getPossibleStates(tag); + Map anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings"); + if (anotherSetting != null) { + for (ImmutableBlockState possibleState : possibleStates) { + possibleState.setSettings(BlockSettings.ofFullCopy(possibleState.settings(), anotherSetting)); + } + } + String appearanceName = ResourceConfigUtils.getAsString(variantSection.get("appearance")); + if (appearanceName != null) { + BlockStateAppearance appearance = appearances.get(appearanceName); + if (appearance == null) { + throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearanceName); + } + for (ImmutableBlockState possibleState : possibleStates) { + possibleState.setVanillaBlockState(appearance.blockState()); + appearance.blockEntityRenderer().ifPresent(possibleState::setConstantRenderers); + } + } + } + // 为没有外观的方块状态填充 + for (ImmutableBlockState blockState : states) { + if (blockState.vanillaBlockState() == null) { + blockState.setVanillaBlockState(anyAppearanceState); + } + } + } + + // 获取方块实体行为 + EntityBlockBehavior entityBlockBehavior = blockBehavior.getEntityBehavior(); + boolean isEntityBlock = entityBlockBehavior != null; + + // 绑定行为 + for (ImmutableBlockState blockState : states) { + blockState.setBehavior(blockBehavior); + if (isEntityBlock) { + blockState.setBlockEntityType(entityBlockBehavior.blockEntityType()); + } + } + + // 添加方块 + addBlockInternal(customBlock); + + }, () -> GsonHelper.get().toJson(section))); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java index d62c103d8..298de8ccd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java @@ -1,9 +1,6 @@ package net.momirealms.craftengine.core.block; -import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; -import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; -import net.momirealms.craftengine.core.block.parser.BlockNbtParser; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.loot.LootTable; @@ -11,7 +8,6 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; 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.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; @@ -23,79 +19,31 @@ import java.util.*; import java.util.function.BiFunction; public abstract class AbstractCustomBlock implements CustomBlock { - protected final Holder holder; - protected final Key id; + protected final Holder.Reference holder; protected final BlockStateVariantProvider variantProvider; - protected final Map> properties; - protected final BlockBehavior behavior; protected final BiFunction placementFunction; protected final ImmutableBlockState defaultState; protected final Map>> events; @Nullable protected final LootTable lootTable; + protected BlockBehavior behavior = EmptyBlockBehavior.INSTANCE; protected AbstractCustomBlock( - @NotNull Key id, @NotNull Holder.Reference holder, - @NotNull Map> properties, - @NotNull Map appearances, - @NotNull Map variantMapper, - @NotNull BlockSettings settings, + @NotNull BlockStateVariantProvider variantProvider, @NotNull Map>> events, - @Nullable List> behaviorConfig, @Nullable LootTable lootTable ) { - holder.bindValue(this); this.holder = holder; - this.id = id; this.lootTable = lootTable; - this.properties = ImmutableMap.copyOf(properties); this.events = events; - this.variantProvider = new BlockStateVariantProvider(holder, ImmutableBlockState::new, properties); + this.variantProvider = variantProvider; this.defaultState = this.variantProvider.getDefaultState(); - this.behavior = setupBehavior(behaviorConfig); List> placements = new ArrayList<>(4); - for (Map.Entry> propertyEntry : this.properties.entrySet()) { + for (Map.Entry> propertyEntry : this.variantProvider.properties().entrySet()) { placements.add(Property.createStateForPlacement(propertyEntry.getKey(), propertyEntry.getValue())); } this.placementFunction = composite(placements); - EntityBlockBehavior entityBlockBehavior = this.behavior.getEntityBehavior(); - boolean isEntityBlock = entityBlockBehavior != null; - - for (Map.Entry entry : variantMapper.entrySet()) { - String nbtString = entry.getKey(); - CompoundTag tag = BlockNbtParser.deserialize(this, nbtString); - if (tag == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString); - } - List possibleStates = this.getPossibleStates(tag); - if (possibleStates.size() != 1) { - throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", nbtString); - } - BlockStateVariant blockStateVariant = entry.getValue(); - BlockStateAppearance blockStateAppearance = appearances.get(blockStateVariant.appearance()); - // Late init states - ImmutableBlockState state = possibleStates.getFirst(); - state.setSettings(blockStateVariant.settings()); - state.setVanillaBlockState(blockStateAppearance.blockState()); - state.setCustomBlockState(blockStateVariant.blockState()); - blockStateAppearance.blockEntityRenderer().ifPresent(state::setConstantRenderers); - } - - // double check if there's any invalid state - for (ImmutableBlockState state : this.variantProvider().states()) { - state.setBehavior(this.behavior); - if (state.settings() == null) { - state.setSettings(settings); - } - if (isEntityBlock) { - state.setBlockEntityType(entityBlockBehavior.blockEntityType()); - } - } - } - - protected BlockBehavior setupBehavior(List> behaviorConfig) { - return EmptyBlockBehavior.INSTANCE; } private static BiFunction composite(List> placements) { @@ -137,28 +85,16 @@ public abstract class AbstractCustomBlock implements CustomBlock { @NotNull @Override public final Key id() { - return this.id; + return this.holder.key().location(); + } + + public void setBehavior(@Nullable BlockBehavior behavior) { + this.behavior = behavior; } @Override public List getPossibleStates(CompoundTag nbt) { - List tempStates = new ArrayList<>(); - tempStates.add(defaultState()); - for (Property property : this.variantProvider.getDefaultState().getProperties()) { - Tag value = nbt.get(property.name()); - if (value != null) { - tempStates.replaceAll(immutableBlockState -> ImmutableBlockState.with(immutableBlockState, property, property.unpack(value))); - } else { - List newStates = new ArrayList<>(); - for (ImmutableBlockState state : tempStates) { - for (Object possibleValue : property.possibleValues()) { - newStates.add(ImmutableBlockState.with(state, property, possibleValue)); - } - } - tempStates = newStates; - } - } - return tempStates; + return this.variantProvider.getPossibleStates(nbt); } @Override @@ -179,12 +115,12 @@ public abstract class AbstractCustomBlock implements CustomBlock { @Override public @Nullable Property getProperty(String name) { - return this.properties.get(name); + return this.variantProvider.getProperty(name); } @Override public @NotNull Collection> properties() { - return this.properties.values(); + return this.variantProvider.properties().values(); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java index d393d4b9d..2997c5dfa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockSounds.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.block; import net.momirealms.craftengine.core.sound.SoundData; -import net.momirealms.craftengine.core.util.Key; import java.util.Map; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java index 445f9c518..eaa50da56 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java @@ -9,11 +9,11 @@ import java.util.*; import java.util.stream.Collectors; public class BlockStateHolder { - protected final Holder owner; + protected final Holder.Reference owner; private final Reference2ObjectArrayMap, Comparable> propertyMap; private Map, ImmutableBlockState[]> withMap; - public BlockStateHolder(Holder owner, Reference2ObjectArrayMap, Comparable> propertyMap) { + public BlockStateHolder(Holder.Reference owner, Reference2ObjectArrayMap, Comparable> propertyMap) { this.owner = owner; this.propertyMap = new Reference2ObjectArrayMap<>(propertyMap); } @@ -39,9 +39,9 @@ public class BlockStateHolder { @Override public String toString() { if (this.propertyMap.isEmpty()) { - return this.owner.value().id().toString(); + return this.owner.key().location().toString(); } - return this.owner.value().id() + "[" + getPropertiesAsString() + "]"; + return this.owner.key().location() + "[" + getPropertiesAsString() + "]"; } public String getPropertiesAsString() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java deleted file mode 100644 index 8a27403c8..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariant.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.momirealms.craftengine.core.block; - -public class BlockStateVariant { - private final String appearance; - private final BlockSettings settings; - private final BlockStateWrapper blockState; - - public BlockStateVariant(String appearance, BlockSettings settings, BlockStateWrapper blockState) { - this.appearance = appearance; - this.settings = settings; - this.blockState = blockState; - } - - public String appearance() { - return appearance; - } - - public BlockSettings settings() { - return settings; - } - - public BlockStateWrapper blockState() { - return blockState; - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariantProvider.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariantProvider.java index 8b131563f..75c6c9080 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariantProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateVariantProvider.java @@ -8,6 +8,8 @@ import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.Pair; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -23,7 +25,7 @@ public final class BlockStateVariantProvider { private final ImmutableList states; private final Holder owner; - public BlockStateVariantProvider(Holder owner, Factory, ImmutableBlockState> factory, Map> propertiesMap) { + public BlockStateVariantProvider(Holder.Reference owner, Factory, ImmutableBlockState> factory, Map> propertiesMap) { this.owner = owner; this.properties = ImmutableSortedMap.copyOf(propertiesMap); @@ -59,6 +61,27 @@ public final class BlockStateVariantProvider { this.states = ImmutableList.copyOf(list); } + public List getPossibleStates(CompoundTag nbt) { + List tempStates = new ArrayList<>(); + ImmutableBlockState defaultState = getDefaultState(); + tempStates.add(defaultState); + for (Property property : defaultState.getProperties()) { + Tag value = nbt.get(property.name()); + if (value != null) { + tempStates.replaceAll(immutableBlockState -> ImmutableBlockState.with(immutableBlockState, property, property.unpack(value))); + } else { + List newStates = new ArrayList<>(); + for (ImmutableBlockState state : tempStates) { + for (Object possibleValue : property.possibleValues()) { + newStates.add(ImmutableBlockState.with(state, property, possibleValue)); + } + } + tempStates = newStates; + } + } + return tempStates; + } + public interface Factory { S create(O owner, Reference2ObjectArrayMap, Comparable> propertyMap); } @@ -80,6 +103,11 @@ public final class BlockStateVariantProvider { return this.owner; } + @NotNull + public ImmutableSortedMap> properties() { + return this.properties; + } + @Nullable public Property getProperty(String name) { return this.properties.get(name); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java index 744d0f4c9..8f71a3707 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java @@ -40,23 +40,4 @@ public interface CustomBlock { ImmutableBlockState getStateForPlacement(BlockPlaceContext context); void setPlacedBy(BlockPlaceContext context, ImmutableBlockState state); - - interface Builder { - - Builder events(Map>> events); - - Builder appearances(Map appearances); - - Builder behavior(List> behavior); - - Builder lootTable(LootTable lootTable); - - Builder properties(Map> properties); - - Builder settings(BlockSettings settings); - - Builder variantMapper(Map variantMapper); - - @NotNull CustomBlock build(); - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java index a6aa4e0f6..a095e3dc4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/EmptyBlock.java @@ -1,18 +1,32 @@ package net.momirealms.craftengine.core.block; +import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; +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 java.util.List; import java.util.Map; public final class EmptyBlock extends AbstractCustomBlock { - public static EmptyBlock INSTANCE; - public static ImmutableBlockState STATE; + public static final EmptyBlock INSTANCE; + public static final ImmutableBlockState STATE; - public EmptyBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), List.of(), null); - INSTANCE = this; - STATE = defaultState(); + static { + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK) + .registerForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), Key.withDefaultNamespace("empty"))); + INSTANCE = new EmptyBlock(holder); + holder.bindValue(INSTANCE); + STATE = INSTANCE.defaultState(); + STATE.setSettings(BlockSettings.of()); + STATE.setBehavior(EmptyBlockBehavior.INSTANCE); + } + + private EmptyBlock(Holder.Reference holder) { + super(holder, new BlockStateVariantProvider(holder, ImmutableBlockState::new, Map.of()), Map.of(), null); + } + + public static void initialize() { } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 18e6460d2..8a68b9527 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -35,7 +35,7 @@ public final class ImmutableBlockState extends BlockStateHolder { private BlockEntityElementConfig[] renderers; ImmutableBlockState( - Holder owner, + Holder.Reference owner, Reference2ObjectArrayMap, Comparable> propertyMap ) { super(owner, propertyMap); @@ -129,7 +129,7 @@ public final class ImmutableBlockState extends BlockStateHolder { public CompoundTag toNbtToSave(CompoundTag properties) { CompoundTag tag = new CompoundTag(); tag.put("properties", properties); - tag.put("id", NBT.createString(this.owner.value().id().asString())); + tag.put("id", NBT.createString(this.owner.key().location().asString())); return tag; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java index 3c16dcae3..abd181734 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java @@ -2,18 +2,16 @@ package net.momirealms.craftengine.core.block; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.momirealms.craftengine.core.registry.Holder; -import net.momirealms.craftengine.core.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; import java.util.HashMap; -import java.util.List; import java.util.Map; public final class InactiveCustomBlock extends AbstractCustomBlock { private final Map cachedData = new HashMap<>(); - public InactiveCustomBlock(Key id, Holder.Reference holder) { - super(id, holder, Map.of(), Map.of(), Map.of(), BlockSettings.of(), Map.of(), List.of(), null); + public InactiveCustomBlock(Holder.Reference holder) { + super(holder, new BlockStateVariantProvider(holder, ImmutableBlockState::new, Map.of()), Map.of(), null); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockNbtParser.java b/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockNbtParser.java index 151709a49..176b0d177 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockNbtParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/parser/BlockNbtParser.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.block.parser; +import net.momirealms.craftengine.core.block.BlockStateVariantProvider; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.util.StringReader; @@ -7,11 +8,13 @@ import net.momirealms.sparrow.nbt.CompoundTag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.function.Function; + public final class BlockNbtParser { private BlockNbtParser() {} @Nullable - public static CompoundTag deserialize(@NotNull CustomBlock block, @NotNull String data) { + public static CompoundTag deserialize(@NotNull Function> propertyProvider, @NotNull String data) { StringReader reader = StringReader.simple(data); CompoundTag properties = new CompoundTag(); while (reader.canRead()) { @@ -24,7 +27,7 @@ public final class BlockNbtParser { if (propertyValue.isEmpty()) { return null; } - Property property = block.getProperty(propertyName); + Property property = propertyProvider.apply(propertyName); if (property != null) { property.createOptionalTag(propertyValue).ifPresent(tag -> { properties.put(propertyName, tag); @@ -38,4 +41,14 @@ public final class BlockNbtParser { } return properties; } + + @Nullable + public static CompoundTag deserialize(@NotNull CustomBlock block, @NotNull String data) { + return deserialize(block::getProperty, data); + } + + @Nullable + public static CompoundTag deserialize(@NotNull BlockStateVariantProvider variantProvider, @NotNull String data) { + return deserialize(variantProvider::getProperty, data); + } } 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 0dee19193..c887cb246 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 @@ -28,6 +28,7 @@ import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.plugin.logger.Debugger; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.util.*; import org.incendo.cloud.suggestion.Suggestion; @@ -424,17 +425,27 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } // 当模型值完成分配的时候 - customModelDataFuture.whenComplete((customModelData, throwable) -> ResourceConfigUtils.runCatching(path, node, () -> { - + customModelDataFuture.whenComplete((cmd, throwable) -> ResourceConfigUtils.runCatching(path, node, () -> { + int customModelData; if (throwable != null) { // 检测custom model data 冲突 if (throwable instanceof IdAllocator.IdConflictException exception) { - throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_conflict", String.valueOf(exception.id()), exception.previousOwner()); + if (section.containsKey("model") || section.containsKey("legacy-model")) { + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data.conflict", String.valueOf(exception.id()), exception.previousOwner()); + } + customModelData = exception.id(); } // custom model data 已被用尽,不太可能 else if (throwable instanceof IdAllocator.IdExhaustedException) { - throw new LocalizedResourceConfigException("warning.config.item.custom_model_data_exhausted"); + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data.exhausted"); } + // 未知错误 + else { + Debugger.ITEM.warn(() -> "Unknown error while allocating custom model data.", throwable); + return; + } + } else { + customModelData = cmd; } // item model 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 21399de3d..f27f4effd 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 @@ -6,13 +6,10 @@ 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.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.ResourceKey; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; import java.util.Map; public class ItemBehaviors { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PendingConfigSection.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PendingConfigSection.java new file mode 100644 index 000000000..db74096e4 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PendingConfigSection.java @@ -0,0 +1,9 @@ +package net.momirealms.craftengine.core.pack; + +import net.momirealms.craftengine.core.util.Key; + +import java.nio.file.Path; +import java.util.Map; + +public record PendingConfigSection(Pack pack, Path path, String node, Key id, Map config) { +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java index a4fe866f6..5977120db 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java @@ -7,6 +7,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import net.momirealms.craftengine.core.util.FileUtils; import net.momirealms.craftengine.core.util.GsonHelper; +import net.momirealms.craftengine.core.util.Pair; import java.io.IOException; import java.nio.file.Files; @@ -57,6 +58,9 @@ public class IdAllocator { continue; } allocateId(id, future); + } else { + // 避免其他条目分配到过时的值上 + this.occupiedIdSet.set(entry.getValue()); } } @@ -120,6 +124,18 @@ public class IdAllocator { return CompletableFuture.completedFuture(id); } + public List> getFixedIdsBetween(int minId, int maxId) { + BiMap inverse = this.forcedIdMap.inverse(); + List> result = new ArrayList<>(); + for (int i = minId; i <= maxId; i++) { + String s = inverse.get(i); + if (s != null) { + result.add(Pair.of(s, i)); + } + } + return result; + } + /** * 请求自动分配ID * @param name 名称 @@ -205,8 +221,6 @@ public class IdAllocator { * 保存缓存到文件 */ public void saveToCache() throws IOException { - FileUtils.createDirectoriesSafe(this.cacheFilePath.getParent()); - // 创建按ID排序的TreeMap Map sortedById = new TreeMap<>(); for (Map.Entry entry : this.cachedIdMap.entrySet()) { @@ -219,7 +233,14 @@ public class IdAllocator { sortedJsonObject.addProperty(entry.getValue(), entry.getKey()); } - GsonHelper.writeJsonFile(sortedJsonObject, this.cacheFilePath); + if (sortedJsonObject.isEmpty()) { + if (Files.exists(this.cacheFilePath)) { + Files.delete(this.cacheFilePath); + } + } else { + FileUtils.createDirectoriesSafe(this.cacheFilePath.getParent()); + GsonHelper.writeJsonFile(sortedJsonObject, this.cacheFilePath); + } } public static class IdConflictException extends RuntimeException { 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 b1e319931..c746856fa 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.registry; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceKey; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; @@ -89,7 +90,7 @@ public interface Holder { } @Override - public String toString() { + public @NotNull String toString() { return "Direct{" + this.value + "}"; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java index b1a135387..ee688e805 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ResourceConfigUtils.java @@ -23,6 +23,13 @@ public final class ResourceConfigUtils { return raw != null ? function.apply(raw) : defaultValue; } + public static String getAsString(@Nullable Object raw) { + if (raw == null) { + return null; + } + return raw.toString(); + } + public static > E getAsEnum(Object o, Class clazz, E defaultValue) { if (o == null) { return defaultValue; 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 36d420260..1f0ee3319 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 @@ -76,7 +76,7 @@ public final class DefaultSectionSerializer { Holder owner = BuiltInRegistries.BLOCK.get(key).orElseGet(() -> { Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder( ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), key)); - InactiveCustomBlock inactiveBlock = new InactiveCustomBlock(key, holder); + InactiveCustomBlock inactiveBlock = new InactiveCustomBlock(holder); holder.bindValue(inactiveBlock); return holder; }); From bb997cf5ba9319fec470edd1a55c04e5bc2e163e Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sun, 28 Sep 2025 04:30:51 +0800 Subject: [PATCH 075/125] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/behavior/WallBlockItemBehavior.java | 2 - .../default/configuration/templates.yml | 440 +++--------------- 2 files changed, 72 insertions(+), 370 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java index 6e46af6cd..94b5254f5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/WallBlockItemBehavior.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.bukkit.item.behavior; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; @@ -9,7 +8,6 @@ import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; import java.nio.file.Path; import java.util.Map; 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 4403a7a15..044ccbf3a 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -925,121 +925,17 @@ templates#block_states: model: path: ${model_path} variants: - distance=1,persistent=false,waterlogged=false: - appearance: default - distance=2,persistent=false,waterlogged=false: - appearance: default - distance=3,persistent=false,waterlogged=false: - appearance: default - distance=4,persistent=false,waterlogged=false: - appearance: default - distance=5,persistent=false,waterlogged=false: - appearance: default - distance=6,persistent=false,waterlogged=false: - appearance: default - distance=7,persistent=false,waterlogged=false: + waterlogged=false: appearance: default + waterlogged=true: + appearance: waterlogged + settings: + resistance: 1200.0 + burnable: false + fluid-state: water + distance=7: settings: is-randomly-ticking: true - distance=1,persistent=true,waterlogged=false: - appearance: default - distance=2,persistent=true,waterlogged=false: - appearance: default - distance=3,persistent=true,waterlogged=false: - appearance: default - distance=4,persistent=true,waterlogged=false: - appearance: default - distance=5,persistent=true,waterlogged=false: - appearance: default - distance=6,persistent=true,waterlogged=false: - appearance: default - distance=7,persistent=true,waterlogged=false: - appearance: default - distance=1,persistent=false,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=2,persistent=false,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=3,persistent=false,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=4,persistent=false,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=5,persistent=false,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=6,persistent=false,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=7,persistent=false,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - is-randomly-ticking: true - fluid-state: water - distance=1,persistent=true,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=2,persistent=true,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=3,persistent=true,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=4,persistent=true,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=5,persistent=true,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=6,persistent=true,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - distance=7,persistent=true,waterlogged=true: - appearance: waterlogged - settings: - resistance: 1200.0 - burnable: false - fluid-state: water # trapdoor block default:block_state/trapdoor: properties: @@ -1223,260 +1119,132 @@ templates#block_states: x: 180 y: 90 variants: - facing=east,half=bottom,open=false,powered=false,waterlogged=false: + facing=east,half=bottom,open=false,waterlogged=false: appearance: facing=east,half=bottom,open=false,waterlogged=false - facing=east,half=bottom,open=false,powered=true,waterlogged=false: - appearance: facing=east,half=bottom,open=false,waterlogged=false - facing=east,half=bottom,open=true,powered=false,waterlogged=false: + facing=east,half=bottom,open=true,waterlogged=false: appearance: facing=east,half=bottom,open=true,waterlogged=false - facing=east,half=bottom,open=true,powered=true,waterlogged=false: - appearance: facing=east,half=bottom,open=true,waterlogged=false - facing=east,half=top,open=false,powered=false,waterlogged=false: + facing=east,half=top,open=false,waterlogged=false: appearance: facing=east,half=top,open=false,waterlogged=false - facing=east,half=top,open=false,powered=true,waterlogged=false: - appearance: facing=east,half=top,open=false,waterlogged=false - facing=east,half=top,open=true,powered=false,waterlogged=false: + facing=east,half=top,open=true,waterlogged=false: appearance: facing=east,half=top,open=true,waterlogged=false - facing=east,half=top,open=true,powered=true,waterlogged=false: - appearance: facing=east,half=top,open=true,waterlogged=false - facing=north,half=bottom,open=false,powered=false,waterlogged=false: + facing=north,half=bottom,open=false,waterlogged=false: appearance: facing=north,half=bottom,open=false,waterlogged=false - facing=north,half=bottom,open=false,powered=true,waterlogged=false: - appearance: facing=north,half=bottom,open=false,waterlogged=false - facing=north,half=bottom,open=true,powered=false,waterlogged=false: + facing=north,half=bottom,open=true,waterlogged=false: appearance: facing=north,half=bottom,open=true,waterlogged=false - facing=north,half=bottom,open=true,powered=true,waterlogged=false: - appearance: facing=north,half=bottom,open=true,waterlogged=false - facing=north,half=top,open=false,powered=false,waterlogged=false: + facing=north,half=top,open=false,waterlogged=false: appearance: facing=north,half=top,open=false,waterlogged=false - facing=north,half=top,open=false,powered=true,waterlogged=false: - appearance: facing=north,half=top,open=false,waterlogged=false - facing=north,half=top,open=true,powered=false,waterlogged=false: + facing=north,half=top,open=true,waterlogged=false: appearance: facing=north,half=top,open=true,waterlogged=false - facing=north,half=top,open=true,powered=true,waterlogged=false: - appearance: facing=north,half=top,open=true,waterlogged=false - facing=south,half=bottom,open=false,powered=false,waterlogged=false: + facing=south,half=bottom,open=false,waterlogged=false: appearance: facing=south,half=bottom,open=false,waterlogged=false - facing=south,half=bottom,open=false,powered=true,waterlogged=false: - appearance: facing=south,half=bottom,open=false,waterlogged=false - facing=south,half=bottom,open=true,powered=false,waterlogged=false: + facing=south,half=bottom,open=true,waterlogged=false: appearance: facing=south,half=bottom,open=true,waterlogged=false - facing=south,half=bottom,open=true,powered=true,waterlogged=false: - appearance: facing=south,half=bottom,open=true,waterlogged=false - facing=south,half=top,open=false,powered=false,waterlogged=false: + facing=south,half=top,open=false,waterlogged=false: appearance: facing=south,half=top,open=false,waterlogged=false - facing=south,half=top,open=false,powered=true,waterlogged=false: - appearance: facing=south,half=top,open=false,waterlogged=false - facing=south,half=top,open=true,powered=false,waterlogged=false: + facing=south,half=top,open=true,waterlogged=false: appearance: facing=south,half=top,open=true,waterlogged=false - facing=south,half=top,open=true,powered=true,waterlogged=false: - appearance: facing=south,half=top,open=true,waterlogged=false - facing=west,half=bottom,open=false,powered=false,waterlogged=false: + facing=west,half=bottom,open=false,waterlogged=false: appearance: facing=west,half=bottom,open=false,waterlogged=false - facing=west,half=bottom,open=false,powered=true,waterlogged=false: - appearance: facing=west,half=bottom,open=false,waterlogged=false - facing=west,half=bottom,open=true,powered=false,waterlogged=false: + facing=west,half=bottom,open=true,waterlogged=false: appearance: facing=west,half=bottom,open=true,waterlogged=false - facing=west,half=bottom,open=true,powered=true,waterlogged=false: - appearance: facing=west,half=bottom,open=true,waterlogged=false - facing=west,half=top,open=false,powered=false,waterlogged=false: + facing=west,half=top,open=false,waterlogged=false: appearance: facing=west,half=top,open=false,waterlogged=false - facing=west,half=top,open=false,powered=true,waterlogged=false: - appearance: facing=west,half=top,open=false,waterlogged=false - facing=west,half=top,open=true,powered=false,waterlogged=false: + facing=west,half=top,open=true,waterlogged=false: appearance: facing=west,half=top,open=true,waterlogged=false - facing=west,half=top,open=true,powered=true,waterlogged=false: - appearance: facing=west,half=top,open=true,waterlogged=false - facing=east,half=bottom,open=false,powered=false,waterlogged=true: + facing=east,half=bottom,open=false,waterlogged=true: appearance: facing=east,half=bottom,open=false,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=east,half=bottom,open=false,powered=true,waterlogged=true: - appearance: facing=east,half=bottom,open=false,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=east,half=bottom,open=true,powered=false,waterlogged=true: + facing=east,half=bottom,open=true,waterlogged=true: appearance: facing=east,half=bottom,open=true,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=east,half=bottom,open=true,powered=true,waterlogged=true: - appearance: facing=east,half=bottom,open=true,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=east,half=top,open=false,powered=false,waterlogged=true: + facing=east,half=top,open=false,waterlogged=true: appearance: facing=east,half=top,open=false,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=east,half=top,open=false,powered=true,waterlogged=true: - appearance: facing=east,half=top,open=false,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=east,half=top,open=true,powered=false,waterlogged=true: + facing=east,half=top,open=true,waterlogged=true: appearance: facing=east,half=top,open=true,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=east,half=top,open=true,powered=true,waterlogged=true: - appearance: facing=east,half=top,open=true,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=north,half=bottom,open=false,powered=false,waterlogged=true: + facing=north,half=bottom,open=false,waterlogged=true: appearance: facing=north,half=bottom,open=false,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=north,half=bottom,open=false,powered=true,waterlogged=true: - appearance: facing=north,half=bottom,open=false,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=north,half=bottom,open=true,powered=false,waterlogged=true: + facing=north,half=bottom,open=true,waterlogged=true: appearance: facing=north,half=bottom,open=true,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=north,half=bottom,open=true,powered=true,waterlogged=true: - appearance: facing=north,half=bottom,open=true,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=north,half=top,open=false,powered=false,waterlogged=true: + facing=north,half=top,open=false,waterlogged=true: appearance: facing=north,half=top,open=false,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=north,half=top,open=false,powered=true,waterlogged=true: - appearance: facing=north,half=top,open=false,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=north,half=top,open=true,powered=false,waterlogged=true: + facing=north,half=top,open=true,waterlogged=true: appearance: facing=north,half=top,open=true,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=north,half=top,open=true,powered=true,waterlogged=true: - appearance: facing=north,half=top,open=true,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=south,half=bottom,open=false,powered=false,waterlogged=true: + facing=south,half=bottom,open=false,waterlogged=true: appearance: facing=south,half=bottom,open=false,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=south,half=bottom,open=false,powered=true,waterlogged=true: - appearance: facing=south,half=bottom,open=false,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=south,half=bottom,open=true,powered=false,waterlogged=true: + facing=south,half=bottom,open=true,waterlogged=true: appearance: facing=south,half=bottom,open=true,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=south,half=bottom,open=true,powered=true,waterlogged=true: - appearance: facing=south,half=bottom,open=true,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=south,half=top,open=false,powered=false,waterlogged=true: + facing=south,half=top,open=false,waterlogged=true: appearance: facing=south,half=top,open=false,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=south,half=top,open=false,powered=true,waterlogged=true: - appearance: facing=south,half=top,open=false,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=south,half=top,open=true,powered=false,waterlogged=true: + facing=south,half=top,open=true,waterlogged=true: appearance: facing=south,half=top,open=true,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=south,half=top,open=true,powered=true,waterlogged=true: - appearance: facing=south,half=top,open=true,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=west,half=bottom,open=false,powered=false,waterlogged=true: + facing=west,half=bottom,open=false,waterlogged=true: appearance: facing=west,half=bottom,open=false,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=west,half=bottom,open=false,powered=true,waterlogged=true: - appearance: facing=west,half=bottom,open=false,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=west,half=bottom,open=true,powered=false,waterlogged=true: + facing=west,half=bottom,open=true,waterlogged=true: appearance: facing=west,half=bottom,open=true,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=west,half=bottom,open=true,powered=true,waterlogged=true: - appearance: facing=west,half=bottom,open=true,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=west,half=top,open=false,powered=false,waterlogged=true: + facing=west,half=top,open=false,waterlogged=true: appearance: facing=west,half=top,open=false,waterlogged=true settings: resistance: 1200.0 burnable: false fluid-state: water - facing=west,half=top,open=false,powered=true,waterlogged=true: - appearance: facing=west,half=top,open=false,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water - facing=west,half=top,open=true,powered=false,waterlogged=true: + facing=west,half=top,open=true,waterlogged=true: appearance: facing=west,half=top,open=true,waterlogged=true settings: fluid-state: water - facing=west,half=top,open=true,powered=true,waterlogged=true: - appearance: facing=west,half=top,open=true,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water # door block default:block_state/door: properties: @@ -1654,133 +1422,69 @@ templates#block_states: path: ${model_top_right_open_path} y: 90 variants: - facing=east,half=lower,hinge=left,open=false,powered=true: + facing=east,half=lower,hinge=left,open=false: appearance: facing=east,half=lower,hinge=left,open=false - facing=east,half=lower,hinge=left,open=false,powered=false: - appearance: facing=east,half=lower,hinge=left,open=false - facing=east,half=lower,hinge=right,open=false,powered=true: + facing=east,half=lower,hinge=right,open=false: appearance: facing=east,half=lower,hinge=right,open=false - facing=east,half=lower,hinge=right,open=false,powered=false: - appearance: facing=east,half=lower,hinge=right,open=false - facing=east,half=upper,hinge=left,open=false,powered=true: + facing=east,half=upper,hinge=left,open=false: appearance: facing=east,half=upper,hinge=left,open=false - facing=east,half=upper,hinge=left,open=false,powered=false: - appearance: facing=east,half=upper,hinge=left,open=false - facing=east,half=upper,hinge=right,open=false,powered=true: + facing=east,half=upper,hinge=right,open=false: appearance: facing=east,half=upper,hinge=right,open=false - facing=east,half=upper,hinge=right,open=false,powered=false: - appearance: facing=east,half=upper,hinge=right,open=false - facing=north,half=lower,hinge=left,open=false,powered=true: + facing=north,half=lower,hinge=left,open=false: appearance: facing=north,half=lower,hinge=left,open=false - facing=north,half=lower,hinge=left,open=false,powered=false: - appearance: facing=north,half=lower,hinge=left,open=false - facing=north,half=lower,hinge=right,open=false,powered=true: + facing=north,half=lower,hinge=right,open=false: appearance: facing=north,half=lower,hinge=right,open=false - facing=north,half=lower,hinge=right,open=false,powered=false: - appearance: facing=north,half=lower,hinge=right,open=false - facing=north,half=upper,hinge=left,open=false,powered=true: + facing=north,half=upper,hinge=left,open=false: appearance: facing=north,half=upper,hinge=left,open=false - facing=north,half=upper,hinge=left,open=false,powered=false: - appearance: facing=north,half=upper,hinge=left,open=false - facing=north,half=upper,hinge=right,open=false,powered=true: + facing=north,half=upper,hinge=right,open=false: appearance: facing=north,half=upper,hinge=right,open=false - facing=north,half=upper,hinge=right,open=false,powered=false: - appearance: facing=north,half=upper,hinge=right,open=false - facing=south,half=lower,hinge=left,open=false,powered=true: + facing=south,half=lower,hinge=left,open=false: appearance: facing=south,half=lower,hinge=left,open=false - facing=south,half=lower,hinge=left,open=false,powered=false: - appearance: facing=south,half=lower,hinge=left,open=false - facing=south,half=lower,hinge=right,open=false,powered=true: + facing=south,half=lower,hinge=right,open=false: appearance: facing=south,half=lower,hinge=right,open=false - facing=south,half=lower,hinge=right,open=false,powered=false: - appearance: facing=south,half=lower,hinge=right,open=false - facing=south,half=upper,hinge=left,open=false,powered=true: + facing=south,half=upper,hinge=left,open=false: appearance: facing=south,half=upper,hinge=left,open=false - facing=south,half=upper,hinge=left,open=false,powered=false: - appearance: facing=south,half=upper,hinge=left,open=false - facing=south,half=upper,hinge=right,open=false,powered=true: + facing=south,half=upper,hinge=right,open=false: appearance: facing=south,half=upper,hinge=right,open=false - facing=south,half=upper,hinge=right,open=false,powered=false: - appearance: facing=south,half=upper,hinge=right,open=false - facing=west,half=lower,hinge=left,open=false,powered=true: + facing=west,half=lower,hinge=left,open=false: appearance: facing=west,half=lower,hinge=left,open=false - facing=west,half=lower,hinge=left,open=false,powered=false: - appearance: facing=west,half=lower,hinge=left,open=false - facing=west,half=lower,hinge=right,open=false,powered=true: + facing=west,half=lower,hinge=right,open=false: appearance: facing=west,half=lower,hinge=right,open=false - facing=west,half=lower,hinge=right,open=false,powered=false: - appearance: facing=west,half=lower,hinge=right,open=false - facing=west,half=upper,hinge=left,open=false,powered=true: + facing=west,half=upper,hinge=left,open=false: appearance: facing=west,half=upper,hinge=left,open=false - facing=west,half=upper,hinge=left,open=false,powered=false: - appearance: facing=west,half=upper,hinge=left,open=false - facing=west,half=upper,hinge=right,open=false,powered=true: + facing=west,half=upper,hinge=right,open=false: appearance: facing=west,half=upper,hinge=right,open=false - facing=west,half=upper,hinge=right,open=false,powered=false: - appearance: facing=west,half=upper,hinge=right,open=false - facing=east,half=lower,hinge=left,open=true,powered=true: + facing=east,half=lower,hinge=left,open=true: appearance: facing=east,half=lower,hinge=left,open=true - facing=east,half=lower,hinge=left,open=true,powered=false: - appearance: facing=east,half=lower,hinge=left,open=true - facing=east,half=lower,hinge=right,open=true,powered=true: + facing=east,half=lower,hinge=right,open=true: appearance: facing=east,half=lower,hinge=right,open=true - facing=east,half=lower,hinge=right,open=true,powered=false: - appearance: facing=east,half=lower,hinge=right,open=true - facing=east,half=upper,hinge=left,open=true,powered=true: + facing=east,half=upper,hinge=left,open=true: appearance: facing=east,half=upper,hinge=left,open=true - facing=east,half=upper,hinge=left,open=true,powered=false: - appearance: facing=east,half=upper,hinge=left,open=true - facing=east,half=upper,hinge=right,open=true,powered=true: + facing=east,half=upper,hinge=right,open=true: appearance: facing=east,half=upper,hinge=right,open=true - facing=east,half=upper,hinge=right,open=true,powered=false: - appearance: facing=east,half=upper,hinge=right,open=true - facing=north,half=lower,hinge=left,open=true,powered=true: + facing=north,half=lower,hinge=left,open=true: appearance: facing=north,half=lower,hinge=left,open=true - facing=north,half=lower,hinge=left,open=true,powered=false: - appearance: facing=north,half=lower,hinge=left,open=true - facing=north,half=lower,hinge=right,open=true,powered=true: + facing=north,half=lower,hinge=right,open=true: appearance: facing=north,half=lower,hinge=right,open=true - facing=north,half=lower,hinge=right,open=true,powered=false: - appearance: facing=north,half=lower,hinge=right,open=true - facing=north,half=upper,hinge=left,open=true,powered=true: + facing=north,half=upper,hinge=left,open=true: appearance: facing=north,half=upper,hinge=left,open=true - facing=north,half=upper,hinge=left,open=true,powered=false: - appearance: facing=north,half=upper,hinge=left,open=true - facing=north,half=upper,hinge=right,open=true,powered=true: + facing=north,half=upper,hinge=right,open=true: appearance: facing=north,half=upper,hinge=right,open=true - facing=north,half=upper,hinge=right,open=true,powered=false: - appearance: facing=north,half=upper,hinge=right,open=true - facing=south,half=lower,hinge=left,open=true,powered=true: + facing=south,half=lower,hinge=left,open=true: appearance: facing=south,half=lower,hinge=left,open=true - facing=south,half=lower,hinge=left,open=true,powered=false: - appearance: facing=south,half=lower,hinge=left,open=true - facing=south,half=lower,hinge=right,open=true,powered=true: + facing=south,half=lower,hinge=right,open=true: appearance: facing=south,half=lower,hinge=right,open=true - facing=south,half=lower,hinge=right,open=true,powered=false: - appearance: facing=south,half=lower,hinge=right,open=true - facing=south,half=upper,hinge=left,open=true,powered=true: + facing=south,half=upper,hinge=left,open=true: appearance: facing=south,half=upper,hinge=left,open=true - facing=south,half=upper,hinge=left,open=true,powered=false: - appearance: facing=south,half=upper,hinge=left,open=true - facing=south,half=upper,hinge=right,open=true,powered=true: + facing=south,half=upper,hinge=right,open=true: appearance: facing=south,half=upper,hinge=right,open=true - facing=south,half=upper,hinge=right,open=true,powered=false: - appearance: facing=south,half=upper,hinge=right,open=true - facing=west,half=lower,hinge=left,open=true,powered=true: + facing=west,half=lower,hinge=left,open=true: appearance: facing=west,half=lower,hinge=left,open=true - facing=west,half=lower,hinge=left,open=true,powered=false: - appearance: facing=west,half=lower,hinge=left,open=true - facing=west,half=lower,hinge=right,open=true,powered=true: + facing=west,half=lower,hinge=right,open=true: appearance: facing=west,half=lower,hinge=right,open=true - facing=west,half=lower,hinge=right,open=true,powered=false: - appearance: facing=west,half=lower,hinge=right,open=true - facing=west,half=upper,hinge=left,open=true,powered=true: + facing=west,half=upper,hinge=left,open=true: appearance: facing=west,half=upper,hinge=left,open=true - facing=west,half=upper,hinge=left,open=true,powered=false: - appearance: facing=west,half=upper,hinge=left,open=true - facing=west,half=upper,hinge=right,open=true,powered=true: - appearance: facing=west,half=upper,hinge=right,open=true - facing=west,half=upper,hinge=right,open=true,powered=false: + facing=west,half=upper,hinge=right,open=true: appearance: facing=west,half=upper,hinge=right,open=true # fence gate block default:block_state/fence_gate: From 7300f0e278bb5ceaa8dd19b01dc0d2ebf61102ff Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sun, 28 Sep 2025 05:30:26 +0800 Subject: [PATCH 076/125] =?UTF-8?q?=E6=81=A2=E5=A4=8D=E6=96=B9=E5=9D=97?= =?UTF-8?q?=E5=9F=BA=E7=A1=80=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 93 +++++++++++++++++-- .../reflection/minecraft/CoreReflections.java | 20 ++++ .../src/main/resources/translations/de.yml | 1 - .../src/main/resources/translations/en.yml | 1 - .../src/main/resources/translations/es.yml | 1 - .../src/main/resources/translations/ru_ru.yml | 1 - .../src/main/resources/translations/tr.yml | 1 - .../src/main/resources/translations/zh_cn.yml | 1 - .../core/block/AbstractBlockManager.java | 10 +- .../core/pack/LoadingSequence.java | 6 +- 10 files changed, 113 insertions(+), 22 deletions(-) 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 413fc8cb3..48d1fa1b1 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 @@ -6,15 +6,9 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BlockGenerator; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.*; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.bukkit.util.KeyUtils; -import net.momirealms.craftengine.bukkit.util.RegistryUtils; -import net.momirealms.craftengine.bukkit.util.TagUtils; +import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.behavior.AbstractBlockBehavior; import net.momirealms.craftengine.core.block.behavior.BlockBehaviors; @@ -59,6 +53,8 @@ public final class BukkitBlockManager extends AbstractBlockManager { private final Set replacedBlockSounds = new HashSet<>(); // 用于缓存string形式的方块状态到原版方块状态 private final Map blockStateCache = new HashMap<>(1024); + // 用于临时存储可燃烧自定义方块的列表 + private final List burnableBlocks = new ArrayList<>(); public BukkitBlockManager(BukkitCraftEngine plugin) { super(plugin, RegistryUtils.currentBlockRegistrySize(), Config.serverSideBlocks()); @@ -95,6 +91,11 @@ public final class BukkitBlockManager extends AbstractBlockManager { Arrays.fill(this.blockStateMappings, -1); this.previousClientBoundTags = this.clientBoundTags; this.clientBoundTags = new HashMap<>(); + for (DelegatingBlock block : this.burnableBlocks) { + this.igniteOdds.remove(block); + this.burnOdds.remove(block); + } + this.burnableBlocks.clear(); if (EmptyBlock.STATE != null) Arrays.fill(this.immutableBlockStates, EmptyBlock.STATE); for (DelegatingBlock block : this.customBlocks) { @@ -252,6 +253,82 @@ public final class BukkitBlockManager extends AbstractBlockManager { } } + @Override + protected void applyPlatformSettings(ImmutableBlockState state) { + DelegatingBlockState nmsState = (DelegatingBlockState) state.customBlockState().literalObject(); + nmsState.setBlockState(state); + Object nmsVisualState = state.vanillaBlockState().literalObject(); + + BlockSettings settings = state.settings(); + try { + CoreReflections.field$BlockStateBase$lightEmission.set(nmsState, settings.luminance()); + CoreReflections.field$BlockStateBase$burnable.set(nmsState, settings.burnable()); + CoreReflections.field$BlockStateBase$hardness.set(nmsState, settings.hardness()); + CoreReflections.field$BlockStateBase$replaceable.set(nmsState, settings.replaceable()); + Object mcMapColor = CoreReflections.method$MapColor$byId.invoke(null, settings.mapColor().id); + CoreReflections.field$BlockStateBase$mapColor.set(nmsState, mcMapColor); + CoreReflections.field$BlockStateBase$instrument.set(nmsState, CoreReflections.instance$NoteBlockInstrument$values[settings.instrument().ordinal()]); + CoreReflections.field$BlockStateBase$pushReaction.set(nmsState, CoreReflections.instance$PushReaction$values[settings.pushReaction().ordinal()]); + boolean canOcclude = settings.canOcclude() == Tristate.UNDEFINED ? BlockStateUtils.isOcclude(nmsVisualState) : settings.canOcclude().asBoolean(); + CoreReflections.field$BlockStateBase$canOcclude.set(nmsState, canOcclude); + boolean useShapeForLightOcclusion = settings.useShapeForLightOcclusion() == Tristate.UNDEFINED ? CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.getBoolean(nmsVisualState) : settings.useShapeForLightOcclusion().asBoolean(); + CoreReflections.field$BlockStateBase$useShapeForLightOcclusion.set(nmsState, useShapeForLightOcclusion); + CoreReflections.field$BlockStateBase$isRedstoneConductor.set(nmsState, settings.isRedstoneConductor().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE); + CoreReflections.field$BlockStateBase$isSuffocating.set(nmsState, settings.isSuffocating().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE); + CoreReflections.field$BlockStateBase$isViewBlocking.set(nmsState, settings.isViewBlocking() == Tristate.UNDEFINED ? settings.isSuffocating().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE : (settings.isViewBlocking().asBoolean() ? ALWAYS_TRUE : ALWAYS_FALSE)); + + DelegatingBlock nmsBlock = (DelegatingBlock) BlockStateUtils.getBlockOwner(nmsState); + ObjectHolder shapeHolder = nmsBlock.shapeDelegate(); + shapeHolder.bindValue(new BukkitBlockShape(nmsVisualState, Optional.ofNullable(state.settings().supportShapeBlockState()).map(it -> Objects.requireNonNull(createVanillaBlockState(it), "Illegal block state: " + it).literalObject()).orElse(null))); + ObjectHolder behaviorHolder = nmsBlock.behaviorDelegate(); + behaviorHolder.bindValue(state.behavior()); + + CoreReflections.field$BlockBehaviour$explosionResistance.set(nmsBlock, settings.resistance()); + CoreReflections.field$BlockBehaviour$friction.set(nmsBlock, settings.friction()); + CoreReflections.field$BlockBehaviour$speedFactor.set(nmsBlock, settings.speedFactor()); + CoreReflections.field$BlockBehaviour$jumpFactor.set(nmsBlock, settings.jumpFactor()); + CoreReflections.field$BlockBehaviour$soundType.set(nmsBlock, SoundUtils.toSoundType(settings.sounds())); + + CoreReflections.method$BlockStateBase$initCache.invoke(nmsState); + boolean isConditionallyFullOpaque = canOcclude & useShapeForLightOcclusion; + if (!VersionHelper.isOrAbove1_21_2()) { + CoreReflections.field$BlockStateBase$isConditionallyFullOpaque.set(nmsState, isConditionallyFullOpaque); + } + + if (VersionHelper.isOrAbove1_21_2()) { + int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$lightBlock.getInt(nmsVisualState); + CoreReflections.field$BlockStateBase$lightBlock.set(nmsState, blockLight); + boolean propagatesSkylightDown = settings.propagatesSkylightDown() == Tristate.UNDEFINED ? CoreReflections.field$BlockStateBase$propagatesSkylightDown.getBoolean(nmsVisualState) : settings.propagatesSkylightDown().asBoolean(); + CoreReflections.field$BlockStateBase$propagatesSkylightDown.set(nmsState, propagatesSkylightDown); + } else { + Object cache = CoreReflections.field$BlockStateBase$cache.get(nmsState); + int blockLight = settings.blockLight() != -1 ? settings.blockLight() : CoreReflections.field$BlockStateBase$Cache$lightBlock.getInt(CoreReflections.field$BlockStateBase$cache.get(nmsVisualState)); + CoreReflections.field$BlockStateBase$Cache$lightBlock.set(cache, blockLight); + boolean propagatesSkylightDown = settings.propagatesSkylightDown() == Tristate.UNDEFINED ? CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(CoreReflections.field$BlockStateBase$cache.get(nmsVisualState)) : settings.propagatesSkylightDown().asBoolean(); + CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.set(cache, propagatesSkylightDown); + if (!isConditionallyFullOpaque) { + CoreReflections.field$BlockStateBase$opacityIfCached.set(nmsState, blockLight); + } + } + + CoreReflections.field$BlockStateBase$fluidState.set(nmsState, settings.fluidState() ? MFluids.WATER$defaultState : MFluids.EMPTY$defaultState); + CoreReflections.field$BlockStateBase$isRandomlyTicking.set(nmsState, settings.isRandomlyTicking()); + Object holder = BukkitCraftEngine.instance().blockManager().getMinecraftBlockHolder(state.customBlockState().registryId()); + Set tags = new HashSet<>(); + for (Key tag : settings.tags()) { + tags.add(CoreReflections.method$TagKey$create.invoke(null, MRegistries.BLOCK, KeyUtils.toResourceLocation(tag))); + } + CoreReflections.field$Holder$Reference$tags.set(holder, tags); + if (settings.burnable()) { + this.igniteOdds.put(nmsBlock, settings.burnChance()); + this.burnOdds.put(nmsBlock, settings.fireSpreadChance()); + this.burnableBlocks.add(nmsBlock); + } + } catch (ReflectiveOperationException e) { + this.plugin.logger().warn("Failed to apply platform block settings for block state " + state, e); + } + } + private BlockSounds toBlockSounds(Object soundType) throws ReflectiveOperationException { return new BlockSounds( toSoundData(CoreReflections.field$SoundType$breakSound.get(soundType), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_0_8), 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 0bbb93176..0d4bdd343 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 @@ -1235,6 +1235,16 @@ public final class CoreReflections { ReflectionUtils.getMethod(clazz$PushReaction, new String[] { "values" }) ); + public static final Object[] instance$PushReaction$values; + + static { + try { + instance$PushReaction$values = (Object[]) method$PushReaction$values.invoke(null); + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to init PushReaction", e); + } + } + public static final Class clazz$NoteBlockInstrument = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "world.level.block.state.properties.BlockPropertyInstrument", @@ -1246,6 +1256,16 @@ public final class CoreReflections { ReflectionUtils.getMethod(clazz$NoteBlockInstrument, new String[] { "values" }) ); + public static final Object[] instance$NoteBlockInstrument$values; + + static { + try { + instance$NoteBlockInstrument$values = (Object[]) method$NoteBlockInstrument$values.invoke(null); + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to init NoteBlockInstrument", e); + } + } + public static final Class clazz$BlockStateBase = requireNonNull( BukkitReflectionUtils.findReobfOrMojmapClass( "world.level.block.state.BlockBase$BlockData", diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 1513a684b..a02740112 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -255,7 +255,6 @@ warning.config.block.state.property.invalid_format: "Problem in Datei Problem in Datei gefunden - Beim Block '' fehlt das erforderliche 'state'-Argument für 'state'." warning.config.block.state.missing_properties: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'properties'-Abschnitt für 'states'." warning.config.block.state.missing_appearances: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'appearances'-Abschnitt für 'states'." -warning.config.block.state.missing_variants: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'variants'-Abschnitt für 'states'." warning.config.block.state.variant.invalid_appearance: "Problem in Datei gefunden - Der Block '' hat einen Fehler, dass die Variante '' eine nicht existierende Appearance '' verwendet." warning.config.block.state.invalid_vanilla: "Problem in Datei gefunden - Der Block '' verwendet einen ungültigen Vanilla-Block-State ''." warning.config.block.state.unavailable_vanilla: "Problem in Datei gefunden - Der Block '' verwendet einen nicht verfügbaren Vanilla-Block-State ''. Bitte gib diesen State in der mappings.yml frei." diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 652e823a8..e15c5f89d 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -267,7 +267,6 @@ warning.config.block.state.property.invalid_format: "Issue found in file warning.config.block.state.missing_state: "Issue found in file - The block '' is missing the required 'state' argument for 'state'." warning.config.block.state.missing_properties: "Issue found in file - The block '' is missing the required 'properties' section for 'states'." warning.config.block.state.missing_appearances: "Issue found in file - The block '' is missing the required 'appearances' section for 'states'." -warning.config.block.state.missing_variants: "Issue found in file - The block '' is missing the required 'variants' section for 'states'." warning.config.block.state.entity_renderer.invalid_type: "Issue found in file - The block '' is using an invalid entity renderer type ''." warning.config.block.state.entity_renderer.item_display.missing_item: "Issue found in file - The block '' is missing the required 'item' argument for 'item_display' entity renderer." warning.config.block.state.entity_renderer.text_display.missing_text: "Issue found in file - The block '' is missing the required 'text' argument for 'text_display' entity renderer." diff --git a/common-files/src/main/resources/translations/es.yml b/common-files/src/main/resources/translations/es.yml index d65bc899a..eaa30b979 100644 --- a/common-files/src/main/resources/translations/es.yml +++ b/common-files/src/main/resources/translations/es.yml @@ -178,7 +178,6 @@ warning.config.block.state.property.invalid_format: "Problema encontrado warning.config.block.state.missing_state: "Problema encontrado en el archivo - El bloque '' carece del argumento requerido 'state' para 'state'." warning.config.block.state.missing_properties: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'properties' para 'states'." warning.config.block.state.missing_appearances: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'appearances' para 'states'." -warning.config.block.state.missing_variants: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'variants' para 'states'." warning.config.block.state.variant.invalid_appearance: "Problema encontrado en el archivo - Hay un error en el bloque '' donde la variante '' está usando una apariencia inexistente ''." warning.config.block.state.invalid_vanilla: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla inválido ''." warning.config.block.state.unavailable_vanilla: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla no disponible ''. Por favor libera este estado en el archivo mappings.yml." diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml index be8170d1a..e3d30278c 100644 --- a/common-files/src/main/resources/translations/ru_ru.yml +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -228,7 +228,6 @@ warning.config.block.state.property.invalid_format: "Проблема н 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.invalid_appearance: "Проблема найдена в файле - Блок '' имеет ошибку, что вариант '' использует несуществующий внешний вид ''." warning.config.block.state.invalid_vanilla: "Проблема найдена в файле - Блок '' имеет недействительное состояние ванильного блока ''." warning.config.block.state.unavailable_vanilla: "Проблема найдена в файле - Блок '' использует недоступное состояние ванильного блока ''. Пожалуйста, освободите это состояние в mappings.yml." diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index d283b67c1..b62967f92 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -176,7 +176,6 @@ warning.config.block.state.property.invalid_format: " dosyasında warning.config.block.state.missing_state: " dosyasında sorun bulundu - '' bloğu, 'state' için gerekli 'state' argümanı eksik." warning.config.block.state.missing_properties: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'properties' bölümü eksik." warning.config.block.state.missing_appearances: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'appearances' bölümü eksik." -warning.config.block.state.missing_variants: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'variants' bölümü eksik." warning.config.block.state.variant.invalid_appearance: " dosyasında sorun bulundu - '' bloğunda, '' varyantının var olmayan bir görünüm '' kullandığı bir hata var." warning.config.block.state.invalid_vanilla: " dosyasında sorun bulundu - '' bloğu geçersiz bir vanilya blok durumu '' kullanıyor." warning.config.block.state.unavailable_vanilla: " dosyasında sorun bulundu - '' bloğu kullanılamayan bir vanilya blok durumu '' kullanıyor. Lütfen bu durumu mappings.yml dosyasında serbest bırakın." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 04bea5c58..9d0175d00 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -263,7 +263,6 @@ warning.config.block.state.property.invalid_format: "在文件 warning.config.block.state.missing_state: "在文件 发现问题 - 方块 '' 的 'state' 缺少必需的 'state' 参数" warning.config.block.state.missing_properties: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'properties' 段落" warning.config.block.state.missing_appearances: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'appearances' 段落" -warning.config.block.state.missing_variants: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'variants' 段落" warning.config.block.state.variant.invalid_appearance: "在文件 发现问题 - 方块 '' 的变体 '' 使用了不存在的 appearance ''" warning.config.block.state.invalid_vanilla: "在文件 发现问题 - 方块 '' 使用了无效的原版方块状态 ''" warning.config.block.state.unavailable_vanilla: "在文件 发现问题 - 方块 '' 使用了不可用的原版方块状态 '' 请在 mappings.yml 中释放该状态" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index bd39b0a59..c1a8fd25a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -6,7 +6,6 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.momirealms.craftengine.core.block.behavior.EntityBlockBehavior; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; @@ -14,7 +13,6 @@ import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityEl import net.momirealms.craftengine.core.block.parser.BlockNbtParser; import net.momirealms.craftengine.core.block.properties.Properties; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.item.AbstractItemManager; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; @@ -49,7 +47,6 @@ import java.nio.file.Path; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.function.Predicate; public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager { protected final BlockParser blockParser; @@ -150,7 +147,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Optional.ofNullable(this.byId.get(id)); } - protected void addBlockInternal(CustomBlock customBlock) { + protected void addCustomBlock(CustomBlock customBlock) { // 绑定外观状态等 for (ImmutableBlockState state : customBlock.variantProvider().states()) { int internalId = state.customBlockState().registryId(); @@ -159,6 +156,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.immutableBlockStates[index] = state; this.blockStateMappings[internalId] = appearanceId; this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId); + this.applyPlatformSettings(state); // generate mod assets if (Config.generateModAssets()) { this.modBlockStateOverrides.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(appearanceId)); @@ -167,6 +165,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.byId.put(customBlock.id(), customBlock); } + protected abstract void applyPlatformSettings(ImmutableBlockState state); + @Override public ConfigParser[] parsers() { return new ConfigParser[]{this.blockParser, this.blockStateMappingParser}; @@ -546,7 +546,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } // 添加方块 - addBlockInternal(customBlock); + addCustomBlock(customBlock); }, () -> GsonHelper.get().toJson(section))); } 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 1868cd5fe..71368dae1 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,9 +8,9 @@ public final class LoadingSequence { public static final int GLOBAL_VAR = 10; public static final int LANG = 20; public static final int TRANSLATION = 30; - public static final int BLOCK = 40; - public static final int EQUIPMENT = 50; - public static final int ITEM = 60; + public static final int EQUIPMENT = 40; + public static final int ITEM = 50; + public static final int BLOCK = 60; public static final int FURNITURE = 70; public static final int IMAGE = 80; public static final int RECIPE = 90; From 2aa75f717810c7833f589e4da21990bade5529c2 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sun, 28 Sep 2025 18:59:14 +0800 Subject: [PATCH 077/125] =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=A3=B0=E9=9F=B3par?= =?UTF-8?q?t=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BlockEventListener.java | 64 ++++++--------- .../bukkit/block/BukkitBlockManager.java | 81 ++++++++++++++++--- .../plugin/network/BukkitNetworkManager.java | 44 ++++------ .../core/block/AbstractBlockManager.java | 63 ++++++++------- .../craftengine/core/util/GsonHelper.java | 20 ++--- gradle.properties | 2 +- 6 files changed, 152 insertions(+), 122 deletions(-) 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 e72055d3c..0a6cf5176 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 @@ -73,18 +73,14 @@ public final class BlockEventListener implements Listener { // send sound if the placed block's sounds are removed if (Config.enableSoundSystem()) { Block block = event.getBlock(); - Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData()); - if (blockState != MBlocks.AIR$defaultState) { - Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); - if (this.manager.isBlockSoundRemoved(ownerBlock)) { + Object blockState = BlockStateUtils.getBlockState(block); + if (blockState != MBlocks.AIR$defaultState && BlockStateUtils.isVanillaBlock(blockState)) { + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object soundEvent = FastNMS.INSTANCE.field$SoundType$placeSound(soundType); + Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); + if (this.manager.isPlaceSoundMissing(soundId)) { if (player.getInventory().getItemInMainHand().getType() != Material.DEBUG_STICK) { - try { - Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock); - Object placeSound = CoreReflections.field$SoundType$placeSound.get(soundType); - player.playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(placeSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to get sound type", e); - } + player.playSound(block.getLocation().add(0.5, 0.5, 0.5), soundId.toString(), SoundCategory.BLOCKS, 1f, 0.8f); } return; } @@ -92,23 +88,19 @@ public final class BlockEventListener implements Listener { } // resend sound if the clicked block is interactable on client side if (serverPlayer.shouldResendSound()) { - try { - Block block = event.getBlock(); - Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData()); - Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); - Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock); - Object placeSound = CoreReflections.field$SoundType$placeSound.get(soundType); - player.playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(placeSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to get sound type", e); - } + Block block = event.getBlock(); + Object blockState = BlockStateUtils.getBlockState(block); + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object soundEvent = FastNMS.INSTANCE.field$SoundType$placeSound(soundType); + Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); + player.playSound(block.getLocation().add(0.5, 0.5, 0.5), soundId.toString(), SoundCategory.BLOCKS, 1f, 0.8f); } } @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onPlayerBreak(BlockBreakEvent event) { org.bukkit.block.Block block = event.getBlock(); - Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData()); + Object blockState = BlockStateUtils.getBlockState(block); int stateId = BlockStateUtils.blockStateToId(blockState); Player player = event.getPlayer(); Location location = block.getLocation(); @@ -194,15 +186,11 @@ public final class BlockEventListener implements Listener { } // sound system if (Config.enableSoundSystem()) { - Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); - if (this.manager.isBlockSoundRemoved(ownerBlock)) { - try { - Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock); - Object breakSound = CoreReflections.field$SoundType$breakSound.get(soundType); - player.playSound(block.getLocation().add(0.5, 0.5, 0.5), FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString(), SoundCategory.BLOCKS, 1f, 0.8f); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to get sound type", e); - } + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object soundEvent = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); + Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); + if (this.manager.isBreakSoundMissing(soundId)) { + player.playSound(block.getLocation().add(0.5, 0.5, 0.5), soundId.toString(), SoundCategory.BLOCKS, 1f, 0.8f); } } } @@ -259,15 +247,11 @@ public final class BlockEventListener implements Listener { } player.playSound(location, state.settings().sounds().stepSound().id().toString(), SoundCategory.BLOCKS, state.settings().sounds().stepSound().volume().get(), state.settings().sounds().stepSound().pitch().get()); } else if (Config.enableSoundSystem()) { - Object ownerBlock = BlockStateUtils.getBlockOwner(blockState); - if (this.manager.isBlockSoundRemoved(ownerBlock)) { - try { - Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(ownerBlock); - Object stepSound = CoreReflections.field$SoundType$stepSound.get(soundType); - player.playSound(player.getLocation(), FastNMS.INSTANCE.field$SoundEvent$location(stepSound).toString(), SoundCategory.BLOCKS, 0.15f, 1f); - } catch (ReflectiveOperationException e) { - this.plugin.logger().warn("Failed to get sound type", e); - } + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object soundEvent = FastNMS.INSTANCE.field$SoundType$stepSound(soundType); + Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); + if (this.manager.isStepSoundMissing(soundId)) { + player.playSound(player.getLocation(), soundId.toString(), SoundCategory.BLOCKS, 0.15f, 1f); } } } 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 48d1fa1b1..01f3ab547 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 @@ -1,6 +1,8 @@ package net.momirealms.craftengine.bukkit.block; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import net.momirealms.craftengine.bukkit.block.behavior.UnsafeCompositeBlockBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -31,6 +33,7 @@ import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.lang.reflect.Field; import java.util.*; public final class BukkitBlockManager extends AbstractBlockManager { @@ -40,7 +43,11 @@ public final class BukkitBlockManager extends AbstractBlockManager { private static BukkitBlockManager instance; private final BukkitCraftEngine plugin; // 事件监听器 - private BlockEventListener blockEventListener; + private final BlockEventListener blockEventListener; + // 用于缓存string形式的方块状态到原版方块状态 + private final Map blockStateCache = new HashMap<>(1024); + // 用于临时存储可燃烧自定义方块的列表 + private final List burnableBlocks = new ArrayList<>(); // 可燃烧的方块 private Map igniteOdds; private Map burnOdds; @@ -50,15 +57,15 @@ public final class BukkitBlockManager extends AbstractBlockManager { // 缓存的原版方块tag包 private Object cachedUpdateTagsPacket; // 被移除声音的原版方块 - private final Set replacedBlockSounds = new HashSet<>(); - // 用于缓存string形式的方块状态到原版方块状态 - private final Map blockStateCache = new HashMap<>(1024); - // 用于临时存储可燃烧自定义方块的列表 - private final List burnableBlocks = new ArrayList<>(); + private Set missingPlaceSounds = Set.of(); + private Set missingBreakSounds = Set.of(); + private Set missingHitSounds = Set.of(); + private Set missingStepSounds = Set.of(); public BukkitBlockManager(BukkitCraftEngine plugin) { super(plugin, RegistryUtils.currentBlockRegistrySize(), Config.serverSideBlocks()); this.plugin = plugin; + this.blockEventListener = new BlockEventListener(plugin, this); this.registerServerSideCustomBlocks(Config.serverSideBlocks()); EmptyBlock.initialize(); instance = this; @@ -71,7 +78,6 @@ public final class BukkitBlockManager extends AbstractBlockManager { this.initVanillaBlockSettings(); this.deceiveBukkitRegistry(); this.markVanillaNoteBlocks(); - this.blockEventListener = new BlockEventListener(plugin, this); Arrays.fill(this.immutableBlockStates, EmptyBlock.INSTANCE.defaultState()); this.plugin.networkManager().registerBlockStatePacketListeners(this.blockStateMappings); // 一定要预先初始化一次,预防id超出上限 } @@ -411,8 +417,20 @@ public final class BukkitBlockManager extends AbstractBlockManager { this.clientBoundTags.put(FastNMS.INSTANCE.method$IdMap$getId(MBuiltInRegistries.BLOCK, block).orElseThrow(() -> new IllegalStateException("Block " + id + " not found")), tags); } - public boolean isBlockSoundRemoved(Object block) { - return this.replacedBlockSounds.contains(block); + public boolean isPlaceSoundMissing(Object sound) { + return this.missingPlaceSounds.contains(sound); + } + + public boolean isBreakSoundMissing(Object sound) { + return this.missingBreakSounds.contains(sound); + } + + public boolean isHitSoundMissing(Object sound) { + return this.missingHitSounds.contains(sound); + } + + public boolean isStepSoundMissing(Object sound) { + return this.missingStepSounds.contains(sound); } private void unfreezeRegistry() { @@ -463,6 +481,51 @@ public final class BukkitBlockManager extends AbstractBlockManager { return this.vanillaBlockStateCount; } + @SuppressWarnings("DuplicatedCode") + @Override + protected void processSounds() { + Set affectedBlockSoundTypes = new HashSet<>(); + for (BlockStateWrapper vanillaBlockState : super.tempVisualBlocksInUse) { + affectedBlockSoundTypes.add(FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(vanillaBlockState.literalObject())); + } + + Set placeSounds = new HashSet<>(); + Set breakSounds = new HashSet<>(); + Set stepSounds = new HashSet<>(); + Set hitSounds = new HashSet<>(); + + for (Object soundType : affectedBlockSoundTypes) { + placeSounds.add(FastNMS.INSTANCE.field$SoundEvent$location(FastNMS.INSTANCE.field$SoundType$placeSound(soundType))); + breakSounds.add(FastNMS.INSTANCE.field$SoundEvent$location(FastNMS.INSTANCE.field$SoundType$breakSound(soundType))); + stepSounds.add(FastNMS.INSTANCE.field$SoundEvent$location(FastNMS.INSTANCE.field$SoundType$stepSound(soundType))); + hitSounds.add(FastNMS.INSTANCE.field$SoundEvent$location(FastNMS.INSTANCE.field$SoundType$hitSound(soundType))); + } + + ImmutableMap.Builder soundReplacementBuilder = ImmutableMap.builder(); + for (Object soundId : placeSounds) { + Key previousId = KeyUtils.resourceLocationToKey(soundId); + soundReplacementBuilder.put(previousId, Key.of(previousId.namespace(), "replaced." + previousId.value())); + } + for (Object soundId : breakSounds) { + Key previousId = KeyUtils.resourceLocationToKey(soundId); + soundReplacementBuilder.put(previousId, Key.of(previousId.namespace(), "replaced." + previousId.value())); + } + for (Object soundId : stepSounds) { + Key previousId = KeyUtils.resourceLocationToKey(soundId); + soundReplacementBuilder.put(previousId, Key.of(previousId.namespace(), "replaced." + previousId.value())); + } + for (Object soundId : hitSounds) { + Key previousId = KeyUtils.resourceLocationToKey(soundId); + soundReplacementBuilder.put(previousId, Key.of(previousId.namespace(), "replaced." + previousId.value())); + } + + this.missingPlaceSounds = placeSounds; + this.missingBreakSounds = breakSounds; + this.missingHitSounds = hitSounds; + this.missingStepSounds = stepSounds; + this.soundReplacements = soundReplacementBuilder.buildKeepingLast(); + } + @Override protected CustomBlock createCustomBlock(@NotNull Holder.Reference holder, @NotNull BlockStateVariantProvider variantProvider, 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 3403b6124..733013ca6 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 @@ -1037,8 +1037,10 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes // not a custom block if (BlockStateUtils.isVanillaBlock(stateId)) { if (Config.enableSoundSystem()) { - Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState); - if (BukkitBlockManager.instance().isBlockSoundRemoved(blockOwner)) { + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object soundEvent = FastNMS.INSTANCE.field$SoundType$hitSound(soundType); + Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); + if (BukkitBlockManager.instance().isHitSoundMissing(soundId)) { player.startMiningBlock(pos, blockState, null); return; } @@ -2293,47 +2295,31 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes int state = buf.readInt(); boolean global = buf.readBoolean(); int newState = user.clientModEnabled() ? modBlockStateMapper[state] : blockStateMapper[state]; + Object blockState = BlockStateUtils.idToBlockState(state); + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object soundEvent = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); + Object rawSoundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); if (BlockStateUtils.isVanillaBlock(state)) { - Object blockState = BlockStateUtils.idToBlockState(state); - Object block = BlockStateUtils.getBlockOwner(blockState); - if (BukkitBlockManager.instance().isBlockSoundRemoved(block)) { - Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); - Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); - Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString()); - Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId); + if (BukkitBlockManager.instance().isBreakSoundMissing(rawSoundId)) { + Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(KeyUtils.resourceLocationToKey(rawSoundId)); if (mappedSoundId != null) { - Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty()); - Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( - mappedBreakSoundHolder, + FastNMS.INSTANCE.method$Holder$direct(FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty())), CoreReflections.instance$SoundSource$BLOCKS, - blockPos.x() + 0.5, - blockPos.y() + 0.5, - blockPos.z() + 0.5, - 1f, - 0.8F, + blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5, 1f, 0.8F, RandomUtils.generateRandomLong() ); user.sendPacket(packet, true); } } } else { - Object blockState = BlockStateUtils.idToBlockState(state); - Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); - Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); - Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString()); + Key soundId = KeyUtils.resourceLocationToKey(rawSoundId); Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId); Object finalSoundId = KeyUtils.toResourceLocation(mappedSoundId == null ? soundId : mappedSoundId); - Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(finalSoundId, Optional.empty()); - Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( - mappedBreakSoundHolder, + FastNMS.INSTANCE.method$Holder$direct(FastNMS.INSTANCE.constructor$SoundEvent(finalSoundId, Optional.empty())), CoreReflections.instance$SoundSource$BLOCKS, - blockPos.x() + 0.5, - blockPos.y() + 0.5, - blockPos.z() + 0.5, - 1f, - 0.8F, + blockPos.x() + 0.5, blockPos.y() + 0.5, blockPos.z() + 0.5, 1f, 0.8F, RandomUtils.generateRandomLong() ); user.sendPacket(packet, true); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index c1a8fd25a..6687d6731 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -14,10 +14,7 @@ import net.momirealms.craftengine.core.block.parser.BlockNbtParser; import net.momirealms.craftengine.core.block.properties.Properties; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.loot.LootTable; -import net.momirealms.craftengine.core.pack.LoadingSequence; -import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.pack.PendingConfigSection; -import net.momirealms.craftengine.core.pack.ResourceLocation; +import net.momirealms.craftengine.core.pack.*; import net.momirealms.craftengine.core.pack.cache.IdAllocator; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; @@ -65,8 +62,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final Map modBlockStateOverrides = new HashMap<>(); // 根据外观查找真实状态,用于debug指令 protected final Map> appearanceToRealState = new Int2ObjectOpenHashMap<>(); - // 声音映射表,和使用了哪些视觉方块有关 - protected final Map soundReplacements = new HashMap<>(512, 0.5f); // 用于note_block:0这样格式的自动分配 protected final Map> blockStateArranger = new HashMap<>(); // 根据registry id找note_block:x中的x值 @@ -83,6 +78,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final ImmutableBlockState[] immutableBlockStates; // 原版方块的属性缓存 protected final BlockSettings[] vanillaBlockSettings; + // 临时存储哪些视觉方块被使用了 + protected final Set tempVisualBlocksInUse = new HashSet<>(); + // 声音映射表,和使用了哪些视觉方块有关 + protected Map soundReplacements = Map.of(); protected AbstractBlockManager(CraftEngine plugin, int vanillaBlockStateCount, int customBlockCount) { super(plugin); @@ -122,7 +121,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.blockStateOverrides.clear(); this.modBlockStateOverrides.clear(); this.byId.clear(); - this.soundReplacements.clear(); this.blockStateArranger.clear(); this.reversedBlockStateArranger.clear(); this.appearanceToRealState.clear(); @@ -133,8 +131,9 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem @Override public void delayedLoad() { this.initSuggestions(); - this.clearCache(); this.resendTags(); + this.processSounds(); + this.clearCache(); } @Override @@ -147,24 +146,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Optional.ofNullable(this.byId.get(id)); } - protected void addCustomBlock(CustomBlock customBlock) { - // 绑定外观状态等 - for (ImmutableBlockState state : customBlock.variantProvider().states()) { - int internalId = state.customBlockState().registryId(); - int appearanceId = state.vanillaBlockState().registryId(); - int index = internalId - this.vanillaBlockStateCount; - this.immutableBlockStates[index] = state; - this.blockStateMappings[internalId] = appearanceId; - this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId); - this.applyPlatformSettings(state); - // generate mod assets - if (Config.generateModAssets()) { - this.modBlockStateOverrides.put(getBlockOwnerId(state.customBlockState()), this.tempVanillaBlockStateModels.get(appearanceId)); - } - } - this.byId.put(customBlock.id(), customBlock); - } - protected abstract void applyPlatformSettings(ImmutableBlockState state); @Override @@ -203,6 +184,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected void clearCache() { this.tempVanillaBlockStateModels.clear(); + this.tempVisualBlocksInUse.clear(); } protected void initSuggestions() { @@ -238,6 +220,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected abstract int vanillaBlockStateCount(); + protected abstract void processSounds(); + protected abstract CustomBlock createCustomBlock(@NotNull Holder.Reference holder, @NotNull BlockStateVariantProvider variantProvider, @NotNull Map>> events, @@ -538,15 +522,34 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem boolean isEntityBlock = entityBlockBehavior != null; // 绑定行为 - for (ImmutableBlockState blockState : states) { - blockState.setBehavior(blockBehavior); + for (ImmutableBlockState state : states) { if (isEntityBlock) { - blockState.setBlockEntityType(entityBlockBehavior.blockEntityType()); + state.setBlockEntityType(entityBlockBehavior.blockEntityType()); + } + state.setBehavior(blockBehavior); + int internalId = state.customBlockState().registryId(); + int appearanceId = state.vanillaBlockState().registryId(); + int index = internalId - AbstractBlockManager.this.vanillaBlockStateCount; + AbstractBlockManager.this.immutableBlockStates[index] = state; + AbstractBlockManager.this.blockStateMappings[internalId] = appearanceId; + AbstractBlockManager.this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId); + AbstractBlockManager.this.tempVisualBlocksInUse.add(state.vanillaBlockState()); + AbstractBlockManager.this.applyPlatformSettings(state); + // generate mod assets + if (Config.generateModAssets()) { + AbstractBlockManager.this.modBlockStateOverrides.put(BlockManager.createCustomBlockKey(index), Optional.ofNullable(AbstractBlockManager.this.tempVanillaBlockStateModels.get(appearanceId)) + .orElseGet(() -> { + // 如果未指定模型,说明复用原版模型?但是部分模型是多部位模型,无法使用变体解决问题 + // 未来需要靠mod重构彻底解决问题 + JsonObject json = new JsonObject(); + json.addProperty("model", "minecraft:block/air"); + return json; + })); } } // 添加方块 - addCustomBlock(customBlock); + AbstractBlockManager.this.byId.put(customBlock.id(), customBlock); }, () -> GsonHelper.get().toJson(section))); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/GsonHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/GsonHelper.java index 975fcfee0..beb6c42a1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/GsonHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/GsonHelper.java @@ -11,25 +11,19 @@ import java.nio.file.Path; import java.util.List; import java.util.Map; -public class GsonHelper { - private final Gson gson; +public final class GsonHelper { + private static final Gson GSON; - public GsonHelper() { - this.gson = new GsonBuilder() + private GsonHelper() {} + + static { + GSON = new GsonBuilder() .disableHtmlEscaping() .create(); } - public Gson getGson() { - return gson; - } - public static Gson get() { - return SingletonHolder.INSTANCE.getGson(); - } - - private static class SingletonHolder { - private static final GsonHelper INSTANCE = new GsonHelper(); + return GSON; } public static void writeJsonFile(JsonElement json, Path path) throws IOException { diff --git a/gradle.properties b/gradle.properties index e56947eb0..c3f2fe021 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.96 +nms_helper_version=1.0.97 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.33.1 From 66bbe3f6e116604e734aa59a820f5552bb065371 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sun, 28 Sep 2025 20:24:36 +0800 Subject: [PATCH 078/125] =?UTF-8?q?=E5=A3=B0=E9=9F=B3=E9=87=8D=E6=9E=84par?= =?UTF-8?q?t=202?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 35 ++++--- .../block/behavior/ButtonBlockBehavior.java | 32 +++---- .../behavior/DoubleHighBlockItemBehavior.java | 3 - .../item/listener/ItemEventListener.java | 26 +++++- .../plugin/user/BukkitServerPlayer.java | 5 +- .../configuration/blocks/palm_tree.yml | 2 +- .../core/block/AbstractBlockManager.java | 15 ++- .../craftengine/core/block/BlockKeys.java | 31 +++++++ .../craftengine/core/block/CustomBlock.java | 2 - .../craftengine/core/item/ItemKeys.java | 9 +- .../craftengine/core/sound/SoundSet.java | 92 +++++++++++++++++++ .../craftengine/core/sound/Sounds.java | 35 ++----- 12 files changed, 210 insertions(+), 77 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/sound/SoundSet.java 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 01f3ab547..acc7ee28e 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 @@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.block; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import net.momirealms.craftengine.bukkit.block.behavior.UnsafeCompositeBlockBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; @@ -25,6 +24,7 @@ import net.momirealms.craftengine.core.plugin.context.function.Function; import net.momirealms.craftengine.core.plugin.logger.Debugger; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.sound.SoundData; +import net.momirealms.craftengine.core.sound.SoundSet; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import org.bukkit.Bukkit; @@ -33,7 +33,6 @@ import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.lang.reflect.Field; import java.util.*; public final class BukkitBlockManager extends AbstractBlockManager { @@ -61,6 +60,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { private Set missingBreakSounds = Set.of(); private Set missingHitSounds = Set.of(); private Set missingStepSounds = Set.of(); + private Set missingInteractSoundBlocks = Set.of(); public BukkitBlockManager(BukkitCraftEngine plugin) { super(plugin, RegistryUtils.currentBlockRegistrySize(), Config.serverSideBlocks()); @@ -433,6 +433,10 @@ public final class BukkitBlockManager extends AbstractBlockManager { return this.missingStepSounds.contains(sound); } + public boolean isInteractSoundMissing(Key blockType) { + return this.missingInteractSoundBlocks.contains(blockType); + } + private void unfreezeRegistry() { try { CoreReflections.field$MappedRegistry$frozen.set(MBuiltInRegistries.BLOCK, false); @@ -485,7 +489,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { @Override protected void processSounds() { Set affectedBlockSoundTypes = new HashSet<>(); - for (BlockStateWrapper vanillaBlockState : super.tempVisualBlocksInUse) { + for (BlockStateWrapper vanillaBlockState : super.tempVisualBlockStatesInUse) { affectedBlockSoundTypes.add(FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(vanillaBlockState.literalObject())); } @@ -523,6 +527,23 @@ public final class BukkitBlockManager extends AbstractBlockManager { this.missingBreakSounds = breakSounds; this.missingHitSounds = hitSounds; this.missingStepSounds = stepSounds; + + Set missingInteractSoundBlocks = new HashSet<>(); + + for (SoundSet soundSet : SoundSet.getAllSoundSets()) { + for (Key block : soundSet.blocks()) { + if (super.tempVisualBlocksInUse.contains(block)) { + Key openSound = soundSet.openSound(); + soundReplacementBuilder.put(openSound, Key.of(openSound.namespace(), "replaced." + openSound.value())); + Key closeSound = soundSet.closeSound(); + soundReplacementBuilder.put(closeSound, Key.of(closeSound.namespace(), "replaced." + closeSound.value())); + missingInteractSoundBlocks.addAll(soundSet.blocks()); + break; + } + } + } + + this.missingInteractSoundBlocks = missingInteractSoundBlocks; this.soundReplacements = soundReplacementBuilder.buildKeepingLast(); } @@ -533,12 +554,4 @@ public final class BukkitBlockManager extends AbstractBlockManager { @Nullable LootTable lootTable) { return new BukkitCustomBlock(holder, variantProvider, events, lootTable); } - - public boolean isOpenableBlockSoundRemoved(Object blockOwner) { - return false; - } - - public SoundData getRemovedOpenableBlockSound(Object blockOwner, boolean b) { - return null; - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java index afa85f737..956830c86 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ButtonBlockBehavior.java @@ -134,26 +134,26 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { } private void checkPressed(Object thisBlock, Object state, Object level, Object pos) { - Object abstractArrow = this.canButtonBeActivatedByArrows ? FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass( + Object arrow = this.canButtonBeActivatedByArrows ? FastNMS.INSTANCE.method$EntityGetter$getEntitiesOfClass( level, CoreReflections.clazz$AbstractArrow, FastNMS.INSTANCE.method$AABB$move( FastNMS.INSTANCE.method$VoxelShape$bounds(FastNMS.INSTANCE.method$BlockState$getShape( state, level, pos, CoreReflections.instance$CollisionContext$empty )), pos), MEntitySelectors.NO_SPECTATORS).stream().findFirst().orElse(null) : null; - boolean flag = abstractArrow != null; + boolean on = arrow != null; ImmutableBlockState blockState = BlockStateUtils.getOptionalCustomBlockState(state).orElse(null); if (blockState == null) return; boolean poweredValue = blockState.get(this.poweredProperty); - if (flag != poweredValue) { - FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, blockState.with(this.poweredProperty, flag).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); + if (on != poweredValue) { + FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, blockState.with(this.poweredProperty, on).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); updateNeighbours(thisBlock, blockState, level, pos); - playSound(null, level, pos, flag); + playSound(level, pos, on); Object gameEvent = VersionHelper.isOrAbove1_20_5() - ? FastNMS.INSTANCE.method$Holder$direct(flag ? MGameEvents.BLOCK_ACTIVATE : MGameEvents.BLOCK_DEACTIVATE) - : flag ? MGameEvents.BLOCK_ACTIVATE : MGameEvents.BLOCK_DEACTIVATE; - FastNMS.INSTANCE.method$LevelAccessor$gameEvent(level, abstractArrow, gameEvent, pos); + ? FastNMS.INSTANCE.method$Holder$direct(on ? MGameEvents.BLOCK_ACTIVATE : MGameEvents.BLOCK_DEACTIVATE) + : on ? MGameEvents.BLOCK_ACTIVATE : MGameEvents.BLOCK_DEACTIVATE; + FastNMS.INSTANCE.method$LevelAccessor$gameEvent(level, arrow, gameEvent, pos); } - if (flag) { + if (on) { FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.ticksToStayPressed); } } @@ -177,21 +177,21 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, FastNMS.INSTANCE.method$BlockPos$relative(pos, nmsDirection), thisBlock, orientation); } - private void playSound(@Nullable Object player, Object level, Object pos, boolean hitByArrow) { - SoundData soundData = getSound(hitByArrow); + private void playSound(Object level, Object pos, boolean on) { + SoundData soundData = getSound(on); if (soundData == null) return; Object sound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(soundData.id()), Optional.empty()); - FastNMS.INSTANCE.method$LevelAccessor$playSound(level, player, pos, sound, CoreReflections.instance$SoundSource$BLOCKS, soundData.volume().get(), soundData.pitch().get()); + FastNMS.INSTANCE.method$LevelAccessor$playSound(level, null, pos, sound, CoreReflections.instance$SoundSource$BLOCKS, soundData.volume().get(), soundData.pitch().get()); } - private SoundData getSound(boolean isOn) { - return isOn ? this.buttonClickOnSound : this.buttonClickOffSound; + private SoundData getSound(boolean on) { + return on ? this.buttonClickOnSound : this.buttonClickOffSound; } private void press(Object thisBlock, ImmutableBlockState state, Object level, Object pos, @Nullable Object player) { FastNMS.INSTANCE.method$LevelWriter$setBlock(level, pos, state.with(this.poweredProperty, true).customBlockState().literalObject(), UpdateOption.UPDATE_ALL.flags()); FastNMS.INSTANCE.method$ScheduledTickAccess$scheduleBlockTick(level, pos, thisBlock, this.ticksToStayPressed); - playSound(player, level, pos, true); + playSound(level, pos, true); Object gameEvent = VersionHelper.isOrAbove1_20_5() ? FastNMS.INSTANCE.method$Holder$direct(MGameEvents.BLOCK_ACTIVATE) : MGameEvents.BLOCK_ACTIVATE; FastNMS.INSTANCE.method$LevelAccessor$gameEvent(level, player, gameEvent, pos); } @@ -203,7 +203,7 @@ public class ButtonBlockBehavior extends BukkitBlockBehavior { public BlockBehavior create(CustomBlock block, Map arguments) { BooleanProperty powered = (BooleanProperty) ResourceConfigUtils.requireNonNullOrThrow(block.getProperty("powered"), "warning.config.block.behavior.button.missing_powered"); int ticksToStayPressed = ResourceConfigUtils.getAsInt(arguments.getOrDefault("ticks-to-stay-pressed", 30), "ticks-to-stay-pressed"); - boolean canButtonBeActivatedByArrows = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-button-be-activated-by-arrows", true), "can-button-be-activated-by-arrows"); + boolean canButtonBeActivatedByArrows = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("can-be-activated-by-arrows", true), "can-be-activated-by-arrows"); Map sounds = (Map) arguments.get("sounds"); SoundData buttonClickOnSound = null; SoundData buttonClickOffSound = null; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java index 7ad5a1bed..d33b45da1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/DoubleHighBlockItemBehavior.java @@ -1,6 +1,5 @@ package net.momirealms.craftengine.bukkit.item.behavior; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids; @@ -9,10 +8,8 @@ import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.pack.Pack; -import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MiscUtils; import org.bukkit.Location; import org.bukkit.block.BlockState; 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 ce1500a38..2dc58f76d 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 @@ -29,7 +29,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.sound.SoundData; +import net.momirealms.craftengine.core.sound.SoundSet; import net.momirealms.craftengine.core.sound.SoundSource; import net.momirealms.craftengine.core.util.*; import net.momirealms.craftengine.core.world.BlockHitResult; @@ -41,6 +41,7 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Openable; +import org.bukkit.block.data.Powerable; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -219,14 +220,29 @@ public class ItemEventListener implements Listener { } } else { if (Config.enableSoundSystem() && hitResult != null) { - Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState); - if (this.plugin.blockManager().isOpenableBlockSoundRemoved(blockOwner)) { + Key blockOwner = BlockStateUtils.getBlockOwnerIdFromState(blockState); + if (this.plugin.blockManager().isInteractSoundMissing(blockOwner)) { boolean hasItem = player.getInventory().getItemInMainHand().getType() != Material.AIR || player.getInventory().getItemInOffHand().getType() != Material.AIR; boolean flag = player.isSneaking() && hasItem; if (!flag) { if (blockData instanceof Openable openable) { - SoundData soundData = this.plugin.blockManager().getRemovedOpenableBlockSound(blockOwner, !openable.isOpen()); - serverPlayer.playSound(soundData.id(), SoundSource.BLOCK, soundData.volume().get(), soundData.pitch().get()); + SoundSet soundSet = SoundSet.getByBlock(blockOwner); + if (soundSet != null) { + serverPlayer.playSound( + Vec3d.atCenterOf(hitResult.getBlockPos()), + openable.isOpen() ? soundSet.closeSound() : soundSet.openSound(), + SoundSource.BLOCK, + 1, RandomUtils.generateRandomFloat(0.9f, 1)); + } + } else if (blockData instanceof Powerable powerable && !powerable.isPowered()) { + SoundSet soundSet = SoundSet.getByBlock(blockOwner); + if (soundSet != null) { + serverPlayer.playSound( + Vec3d.atCenterOf(hitResult.getBlockPos()), + soundSet.openSound(), + SoundSource.BLOCK, + 1, RandomUtils.generateRandomFloat(0.9f, 1)); + } } } } 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 2c4f7468f..36ed88089 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 @@ -717,9 +717,8 @@ public class BukkitServerPlayer extends Player { // send hit sound if the sound is removed if (currentTick - this.lastHitBlockTime > 3) { - Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(destroyedState); - Object soundType = CoreReflections.field$BlockBehaviour$soundType.get(blockOwner); - Object soundEvent = CoreReflections.field$SoundType$hitSound.get(soundType); + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(destroyedState); + Object soundEvent = FastNMS.INSTANCE.field$SoundType$hitSound(soundType); Object soundId = FastNMS.INSTANCE.field$SoundEvent$location(soundEvent); player.playSound(location, soundId.toString(), SoundCategory.BLOCKS, 0.5F, 0.5F); this.lastHitBlockTime = currentTick; diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 65268063a..61ccd87bc 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -689,7 +689,7 @@ blocks#button: - type: face_attached_horizontal_directional_block - type: button_block ticks-to-stay-pressed: 30 - can-button-be-activated-by-arrows: true + can-be-activated-by-arrows: true sounds: on: minecraft:block.wooden_button.click_on off: minecraft:block.wooden_button.click_off diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 6687d6731..94740912f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -14,7 +14,10 @@ import net.momirealms.craftengine.core.block.parser.BlockNbtParser; import net.momirealms.craftengine.core.block.properties.Properties; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.loot.LootTable; -import net.momirealms.craftengine.core.pack.*; +import net.momirealms.craftengine.core.pack.LoadingSequence; +import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.PendingConfigSection; +import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.cache.IdAllocator; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; @@ -79,7 +82,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 原版方块的属性缓存 protected final BlockSettings[] vanillaBlockSettings; // 临时存储哪些视觉方块被使用了 - protected final Set tempVisualBlocksInUse = new HashSet<>(); + protected final Set tempVisualBlockStatesInUse = new HashSet<>(); + protected final Set tempVisualBlocksInUse = new HashSet<>(); // 声音映射表,和使用了哪些视觉方块有关 protected Map soundReplacements = Map.of(); @@ -184,6 +188,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected void clearCache() { this.tempVanillaBlockStateModels.clear(); + this.tempVisualBlockStatesInUse.clear(); this.tempVisualBlocksInUse.clear(); } @@ -528,12 +533,14 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } state.setBehavior(blockBehavior); int internalId = state.customBlockState().registryId(); - int appearanceId = state.vanillaBlockState().registryId(); + BlockStateWrapper visualState = state.vanillaBlockState(); + int appearanceId = visualState.registryId(); int index = internalId - AbstractBlockManager.this.vanillaBlockStateCount; AbstractBlockManager.this.immutableBlockStates[index] = state; AbstractBlockManager.this.blockStateMappings[internalId] = appearanceId; AbstractBlockManager.this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId); - AbstractBlockManager.this.tempVisualBlocksInUse.add(state.vanillaBlockState()); + AbstractBlockManager.this.tempVisualBlockStatesInUse.add(visualState); + AbstractBlockManager.this.tempVisualBlocksInUse.add(getBlockOwnerId(visualState)); AbstractBlockManager.this.applyPlatformSettings(state); // generate mod assets if (Config.generateModAssets()) { 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 c6b9cd591..ce9cf8079 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 @@ -2,6 +2,8 @@ package net.momirealms.craftengine.core.block; import net.momirealms.craftengine.core.util.Key; +import java.util.List; + public final class BlockKeys { private BlockKeys() {} @@ -243,4 +245,33 @@ public final class BlockKeys { public static final Key BAMBOO_WALL_HANGING_SIGN = Key.of("minecraft:bamboo_wall_hanging_sign"); public static final Key CACTUS = Key.of("minecraft:cactus"); + + public static final List WOODEN_TRAPDOORS = List.of(OAK_TRAPDOOR, SPRUCE_TRAPDOOR, BIRCH_TRAPDOOR, + ACACIA_TRAPDOOR, PALE_OAK_TRAPDOOR, DARK_OAK_TRAPDOOR, MANGROVE_TRAPDOOR, JUNGLE_TRAPDOOR); + public static final List CHERRY_TRAPDOORS = List.of(CHERRY_TRAPDOOR); + public static final List BAMBOO_TRAPDOORS = List.of(BAMBOO_TRAPDOOR); + public static final List NETHER_TRAPDOORS = List.of(WARPED_TRAPDOOR, CRIMSON_TRAPDOOR); + public static final List COPPER_TRAPDOORS = List.of(COPPER_TRAPDOOR, EXPOSED_COPPER_TRAPDOOR, WEATHERED_COPPER_TRAPDOOR, OXIDIZED_COPPER_DOOR, + WAXED_COPPER_TRAPDOOR, WAXED_EXPOSED_COPPER_TRAPDOOR, WAXED_WEATHERED_COPPER_TRAPDOOR, WAXED_OXIDIZED_COPPER_TRAPDOOR); + + public static final List WOODEN_DOORS = List.of(OAK_DOOR, SPRUCE_DOOR, BIRCH_DOOR, + ACACIA_DOOR, PALE_OAK_DOOR, DARK_OAK_DOOR, MANGROVE_DOOR, JUNGLE_DOOR); + public static final List CHERRY_DOORS = List.of(CHERRY_DOOR); + public static final List BAMBOO_DOORS = List.of(BAMBOO_DOOR); + public static final List NETHER_DOORS = List.of(WARPED_DOOR, CRIMSON_DOOR); + public static final List COPPER_DOORS = List.of(COPPER_DOOR, EXPOSED_COPPER_DOOR, WEATHERED_COPPER_DOOR, OXIDIZED_COPPER_DOOR, + WAXED_COPPER_DOOR, WAXED_EXPOSED_COPPER_DOOR, WAXED_WEATHERED_COPPER_DOOR, WAXED_OXIDIZED_COPPER_DOOR); + + public static final List WOODEN_FENCE_GATES = List.of(OAK_FENCE_GATE, SPRUCE_FENCE_GATE, BIRCH_FENCE_GATE, + ACACIA_FENCE_GATE, PALE_OAK_FENCE_GATE, DARK_OAK_FENCE_GATE, MANGROVE_FENCE_GATE, JUNGLE_FENCE_GATE); + public static final List CHERRY_FENCE_GATES = List.of(CHERRY_FENCE_GATE); + public static final List BAMBOO_FENCE_GATES = List.of(BAMBOO_FENCE_GATE); + public static final List NETHER_FENCE_GATES = List.of(WARPED_FENCE_GATE, CRIMSON_FENCE_GATE); + + public static final List WOODEN_BUTTONS = List.of(OAK_BUTTON, SPRUCE_BUTTON, BIRCH_BUTTON, JUNGLE_BUTTON, + ACACIA_BUTTON, DARK_OAK_BUTTON, PALE_OAK_BUTTON, MANGROVE_BUTTON); + public static final List CHERRY_BUTTONS = List.of(CHERRY_BUTTON); + public static final List BAMBOO_BUTTONS = List.of(BAMBOO_BUTTON); + public static final List NETHER_BUTTONS = List.of(CRIMSON_BUTTON, WARPED_BUTTON); + public static final List STONE_BUTTONS = List.of(STONE_BUTTON, POLISHED_BLACKSTONE_BUTTON); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java index 8f71a3707..83932728d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/CustomBlock.java @@ -5,7 +5,6 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.loot.LootTable; 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.util.Key; import net.momirealms.sparrow.nbt.CompoundTag; import org.jetbrains.annotations.NotNull; @@ -13,7 +12,6 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; -import java.util.Map; public interface CustomBlock { diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java index cf0c172e5..33a9ac8c5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/ItemKeys.java @@ -62,11 +62,6 @@ public final class ItemKeys { public static final Key BLACK_DYE = Key.of("minecraft:black_dye"); public static final Key FIREWORK_STAR = Key.of("minecraft:firework_star"); - public static final Key[] AXES = new Key[] { - WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE - }; - - public static final Key[] WATER_BUCKETS = new Key[] { - WATER_BUCKET, COD_BUCKET, SALMON_BUCKET, TROPICAL_FISH_BUCKET, TADPOLE_BUCKET, PUFFERFISH_BUCKET, AXOLOTL_BUCKET - }; + public static final Key[] AXES = new Key[] {WOODEN_AXE, STONE_AXE, IRON_AXE, GOLDEN_AXE, DIAMOND_AXE, NETHERITE_AXE}; + public static final Key[] WATER_BUCKETS = new Key[] {WATER_BUCKET, COD_BUCKET, SALMON_BUCKET, TROPICAL_FISH_BUCKET, TADPOLE_BUCKET, PUFFERFISH_BUCKET, AXOLOTL_BUCKET}; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundSet.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundSet.java new file mode 100644 index 000000000..409f9cd7b --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundSet.java @@ -0,0 +1,92 @@ +package net.momirealms.craftengine.core.sound; + +import net.momirealms.craftengine.core.block.BlockKeys; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public record SoundSet(List blocks, Key openSound, Key closeSound) { + // Trapdoor sound sets + public static final SoundSet WOODEN_TRAPDOOR = new SoundSet(BlockKeys.WOODEN_TRAPDOORS, Sounds.WOODEN_TRAPDOOR_OPEN, Sounds.WOODEN_TRAPDOOR_CLOSE); + public static final SoundSet NETHER_WOOD_TRAPDOOR = new SoundSet(BlockKeys.NETHER_TRAPDOORS, Sounds.NETHER_WOOD_TRAPDOOR_OPEN, Sounds.NETHER_WOOD_TRAPDOOR_CLOSE); + public static final SoundSet BAMBOO_WOOD_TRAPDOOR = new SoundSet(BlockKeys.BAMBOO_TRAPDOORS, Sounds.BAMBOO_WOOD_TRAPDOOR_OPEN, Sounds.BAMBOO_WOOD_TRAPDOOR_CLOSE); + public static final SoundSet CHERRY_WOOD_TRAPDOOR = new SoundSet(BlockKeys.CHERRY_TRAPDOORS, Sounds.CHERRY_WOOD_TRAPDOOR_OPEN, Sounds.CHERRY_WOOD_TRAPDOOR_CLOSE); + public static final SoundSet COPPER_TRAPDOOR = new SoundSet(BlockKeys.COPPER_TRAPDOORS, Sounds.COPPER_TRAPDOOR_OPEN, Sounds.COPPER_TRAPDOOR_CLOSE); + + // Door sound sets + public static final SoundSet WOODEN_DOOR = new SoundSet(BlockKeys.WOODEN_DOORS, Sounds.WOODEN_DOOR_OPEN, Sounds.WOODEN_DOOR_CLOSE); + public static final SoundSet NETHER_WOOD_DOOR = new SoundSet(BlockKeys.NETHER_DOORS, Sounds.NETHER_WOOD_DOOR_OPEN, Sounds.NETHER_WOOD_DOOR_CLOSE); + public static final SoundSet BAMBOO_WOOD_DOOR = new SoundSet(BlockKeys.BAMBOO_DOORS, Sounds.BAMBOO_WOOD_DOOR_OPEN, Sounds.BAMBOO_WOOD_DOOR_CLOSE); + public static final SoundSet CHERRY_WOOD_DOOR = new SoundSet(BlockKeys.CHERRY_DOORS, Sounds.CHERRY_WOOD_DOOR_OPEN, Sounds.CHERRY_WOOD_DOOR_CLOSE); + public static final SoundSet COPPER_DOOR = new SoundSet(BlockKeys.COPPER_DOORS, Sounds.COPPER_DOOR_OPEN, Sounds.COPPER_DOOR_CLOSE); + + // Button sound sets + public static final SoundSet WOODEN_BUTTON = new SoundSet(BlockKeys.WOODEN_BUTTONS, Sounds.WOODEN_BUTTON_CLICK_ON, Sounds.WOODEN_BUTTON_CLICK_OFF); + public static final SoundSet NETHER_WOOD_BUTTON = new SoundSet(BlockKeys.NETHER_BUTTONS, Sounds.NETHER_WOOD_BUTTON_CLICK_ON, Sounds.NETHER_WOOD_BUTTON_CLICK_OFF); + public static final SoundSet BAMBOO_WOOD_BUTTON = new SoundSet(BlockKeys.BAMBOO_BUTTONS, Sounds.BAMBOO_WOOD_BUTTON_CLICK_ON, Sounds.BAMBOO_WOOD_BUTTON_CLICK_OFF); + public static final SoundSet CHERRY_WOOD_BUTTON = new SoundSet(BlockKeys.CHERRY_BUTTONS, Sounds.CHERRY_WOOD_BUTTON_CLICK_ON, Sounds.CHERRY_WOOD_BUTTON_CLICK_OFF); + public static final SoundSet STONE_BUTTON = new SoundSet(BlockKeys.STONE_BUTTONS, Sounds.STONE_BUTTON_CLICK_ON, Sounds.STONE_BUTTON_CLICK_OFF); + + // Fence gate sound sets + public static final SoundSet WOODEN_FENCE_GATE = new SoundSet(BlockKeys.WOODEN_FENCE_GATES, Sounds.WOODEN_FENCE_GATE_OPEN, Sounds.WOODEN_FENCE_GATE_CLOSE); + public static final SoundSet NETHER_WOOD_FENCE_GATE = new SoundSet(BlockKeys.NETHER_FENCE_GATES, Sounds.NETHER_WOOD_FENCE_GATE_OPEN, Sounds.NETHER_WOOD_FENCE_GATE_CLOSE); + public static final SoundSet BAMBOO_WOOD_FENCE_GATE = new SoundSet(BlockKeys.BAMBOO_FENCE_GATES, Sounds.BAMBOO_WOOD_FENCE_GATE_OPEN, Sounds.BAMBOO_WOOD_FENCE_GATE_CLOSE); + public static final SoundSet CHERRY_WOOD_FENCE_GATE = new SoundSet(BlockKeys.CHERRY_FENCE_GATES, Sounds.CHERRY_WOOD_FENCE_GATE_OPEN, Sounds.CHERRY_WOOD_FENCE_GATE_CLOSE); + + // 获取所有声音集合的便捷方法 + public static List getAllSoundSets() { + return List.of( + // Trapdoors + WOODEN_TRAPDOOR, NETHER_WOOD_TRAPDOOR, BAMBOO_WOOD_TRAPDOOR, + CHERRY_WOOD_TRAPDOOR, COPPER_TRAPDOOR, + // Doors + WOODEN_DOOR, NETHER_WOOD_DOOR, BAMBOO_WOOD_DOOR, + CHERRY_WOOD_DOOR, COPPER_DOOR, + // Fence gates + WOODEN_FENCE_GATE, NETHER_WOOD_FENCE_GATE, + BAMBOO_WOOD_FENCE_GATE, CHERRY_WOOD_FENCE_GATE, + // Buttons + WOODEN_BUTTON, NETHER_WOOD_BUTTON, BAMBOO_WOOD_BUTTON, + CHERRY_WOOD_BUTTON, STONE_BUTTON + ); + } + + // 按类型获取声音集合的方法 + public static List getTrapdoorSoundSets() { + return List.of(WOODEN_TRAPDOOR, NETHER_WOOD_TRAPDOOR, BAMBOO_WOOD_TRAPDOOR, + CHERRY_WOOD_TRAPDOOR, COPPER_TRAPDOOR); + } + + public static List getDoorSoundSets() { + return List.of(WOODEN_DOOR, NETHER_WOOD_DOOR, BAMBOO_WOOD_DOOR, + CHERRY_WOOD_DOOR, COPPER_DOOR); + } + + public static List getFenceGateSoundSets() { + return List.of(WOODEN_FENCE_GATE, NETHER_WOOD_FENCE_GATE, + BAMBOO_WOOD_FENCE_GATE, CHERRY_WOOD_FENCE_GATE); + } + + public static List getButtonSoundSets() { + return List.of(WOODEN_BUTTON, NETHER_WOOD_BUTTON, BAMBOO_WOOD_BUTTON, + CHERRY_WOOD_BUTTON, STONE_BUTTON); + } + + private static final Map SOUND_SETS = new HashMap<>(); + + static { + for (SoundSet set : getAllSoundSets()) { + set.blocks.forEach(block -> { + SOUND_SETS.put(block, set); + }); + } + } + + @Nullable + public static SoundSet getByBlock(Key blockType) { + return SOUND_SETS.get(blockType); + } +} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/Sounds.java b/core/src/main/java/net/momirealms/craftengine/core/sound/Sounds.java index a5e6000df..252754c00 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/Sounds.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/Sounds.java @@ -1,35 +1,10 @@ package net.momirealms.craftengine.core.sound; -import net.momirealms.craftengine.core.block.BlockKeys; import net.momirealms.craftengine.core.util.Key; -import java.util.List; - public final class Sounds { private Sounds() {} - public static final List WOODEN_TRAPDOORS = List.of(BlockKeys.OAK_TRAPDOOR, BlockKeys.SPRUCE_TRAPDOOR, BlockKeys.BIRCH_TRAPDOOR, - BlockKeys.ACACIA_TRAPDOOR, BlockKeys.PALE_OAK_TRAPDOOR, BlockKeys.DARK_OAK_TRAPDOOR, BlockKeys.MANGROVE_TRAPDOOR, BlockKeys.JUNGLE_TRAPDOOR); - public static final List CHERRY_TRAPDOORS = List.of(BlockKeys.CHERRY_TRAPDOOR); - public static final List BAMBOO_TRAPDOORS = List.of(BlockKeys.BAMBOO_TRAPDOOR); - public static final List NETHER_TRAPDOORS = List.of(BlockKeys.WARPED_TRAPDOOR, BlockKeys.CRIMSON_TRAPDOOR); - public static final List COPPER_TRAPDOORS = List.of(BlockKeys.COPPER_TRAPDOOR, BlockKeys.EXPOSED_COPPER_TRAPDOOR, BlockKeys.WEATHERED_COPPER_TRAPDOOR, BlockKeys.OXIDIZED_COPPER_DOOR, - BlockKeys.WAXED_COPPER_TRAPDOOR, BlockKeys.WAXED_EXPOSED_COPPER_TRAPDOOR, BlockKeys.WAXED_WEATHERED_COPPER_TRAPDOOR, BlockKeys.WAXED_OXIDIZED_COPPER_TRAPDOOR); - - public static final List WOODEN_DOORS = List.of(BlockKeys.OAK_DOOR, BlockKeys.SPRUCE_DOOR, BlockKeys.BIRCH_DOOR, - BlockKeys.ACACIA_DOOR, BlockKeys.PALE_OAK_DOOR, BlockKeys.DARK_OAK_DOOR, BlockKeys.MANGROVE_DOOR, BlockKeys.JUNGLE_DOOR); - public static final List CHERRY_DOORS = List.of(BlockKeys.CHERRY_DOOR); - public static final List BAMBOO_DOORS = List.of(BlockKeys.BAMBOO_DOOR); - public static final List NETHER_DOORS = List.of(BlockKeys.WARPED_DOOR, BlockKeys.CRIMSON_DOOR); - public static final List COPPER_DOORS = List.of(BlockKeys.COPPER_DOOR, BlockKeys.EXPOSED_COPPER_DOOR, BlockKeys.WEATHERED_COPPER_DOOR, BlockKeys.OXIDIZED_COPPER_DOOR, - BlockKeys.WAXED_COPPER_DOOR, BlockKeys.WAXED_EXPOSED_COPPER_DOOR, BlockKeys.WAXED_WEATHERED_COPPER_DOOR, BlockKeys.WAXED_OXIDIZED_COPPER_DOOR); - - public static final List WOODEN_FENCE_GATES = List.of(BlockKeys.OAK_FENCE_GATE, BlockKeys.SPRUCE_FENCE_GATE, BlockKeys.BIRCH_FENCE_GATE, - BlockKeys.ACACIA_FENCE_GATE, BlockKeys.PALE_OAK_FENCE_GATE, BlockKeys.DARK_OAK_FENCE_GATE, BlockKeys.MANGROVE_FENCE_GATE, BlockKeys.JUNGLE_FENCE_GATE); - public static final List CHERRY_FENCE_GATES = List.of(BlockKeys.CHERRY_FENCE_GATE); - public static final List BAMBOO_FENCE_GATES = List.of(BlockKeys.BAMBOO_FENCE_GATE); - public static final List NETHER_FENCE_GATES = List.of(BlockKeys.WARPED_FENCE_GATE, BlockKeys.CRIMSON_FENCE_GATE); - public static final Key WOODEN_TRAPDOOR_OPEN = Key.of("block.wooden_trapdoor.open"); public static final Key WOODEN_TRAPDOOR_CLOSE = Key.of("block.wooden_trapdoor.close"); public static final Key WOODEN_DOOR_OPEN = Key.of("block.wooden_door.open"); @@ -58,4 +33,14 @@ public final class Sounds { public static final Key COPPER_TRAPDOOR_CLOSE = Key.of("block.copper_trapdoor.close"); public static final Key COPPER_DOOR_OPEN = Key.of("block.copper_door.open"); public static final Key COPPER_DOOR_CLOSE = Key.of("block.copper_door.close"); + public static final Key STONE_BUTTON_CLICK_OFF = Key.of("block.stone_button.click_off"); + public static final Key STONE_BUTTON_CLICK_ON = Key.of("block.stone_button.click_on"); + public static final Key CHERRY_WOOD_BUTTON_CLICK_OFF = Key.of("block.cherry_wood_button.click_off"); + public static final Key CHERRY_WOOD_BUTTON_CLICK_ON = Key.of("block.cherry_wood_button.click_on"); + public static final Key NETHER_WOOD_BUTTON_CLICK_OFF = Key.of("block.nether_wood_button.click_off"); + public static final Key NETHER_WOOD_BUTTON_CLICK_ON = Key.of("block.nether_wood_button.click_on"); + public static final Key BAMBOO_WOOD_BUTTON_CLICK_OFF = Key.of("block.bamboo_wood_button.click_off"); + public static final Key BAMBOO_WOOD_BUTTON_CLICK_ON = Key.of("block.bamboo_wood_button.click_on"); + public static final Key WOODEN_BUTTON_CLICK_OFF = Key.of("block.wooden_button.click_off"); + public static final Key WOODEN_BUTTON_CLICK_ON = Key.of("block.wooden_button.click_on"); } From 1da35c6bb5b8f8414f47562fb09272cb378637f3 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sun, 28 Sep 2025 21:19:44 +0800 Subject: [PATCH 079/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0atlas=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/config.yml | 10 ++- .../core/pack/AbstractPackManager.java | 77 +++++++++++++++---- .../core/plugin/config/Config.java | 14 +++- gradle.properties | 2 +- 4 files changed, 81 insertions(+), 22 deletions(-) diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 4f14758e1..3203ee842 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -23,6 +23,7 @@ resource-pack: method-1: false method-2: false method-3: false # Enable this would increase the resource pack size by 0.67MB + # [Premium Exclusive] # Obfuscate your resource pack obfuscation: enable: false @@ -50,9 +51,13 @@ resource-pack: - "@vanilla_models" bypass-sounds: [] bypass-equipments: [] - # Validate if there are any errors in the resource pack, such as missing textures or models - validate: + # Validate if there is any error in the resource pack, such as missing textures or models + # If your resource pack is compliant with the standard, you can disable validation to improve the resource pack generation speed. + validation: enable: true + # [Premium Exclusive] + # Fix images that are not within the texture atlas. + fix-atlas: true # Define the name of the overlay folders overlay-format: "ce_overlay_{version}" # Allowed values: @@ -138,6 +143,7 @@ resource-pack: type: merge_atlas item: + # [Premium Exclusive] # Make custom-model-data and item-model clientside by default client-bound-model: true # Add a tag on custom name and lore 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 268e9bdc9..f74448582 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 @@ -866,9 +866,6 @@ public abstract class AbstractPackManager implements PackManager { } } } - case "filter", "minecraft:filter" -> { - // todo filter - } case "paletted_permutations", "minecraft:paletted_permutations" -> { JsonArray textures = sourceJson.getAsJsonArray("textures"); if (textures == null) continue; @@ -883,6 +880,9 @@ public abstract class AbstractPackManager implements PackManager { } } } + case "filter", "minecraft:filter" -> { + // todo filter + } } } } @@ -908,28 +908,32 @@ public abstract class AbstractPackManager implements PackManager { Set existingTextures = new HashSet<>(VANILLA_TEXTURES); Map directoryMapper = new HashMap<>(); processAtlas(this.vanillaAtlas, directoryMapper::put, existingTextures::add, texturesInAtlas::add); + Map allAtlas = new HashMap<>(); for (Path rootPath : rootPaths) { Path assetsPath = rootPath.resolve("assets"); if (!Files.isDirectory(assetsPath)) continue; + + Path atlasesFile = assetsPath.resolve("minecraft").resolve("atlases").resolve("blocks.json"); + if (Files.exists(atlasesFile)) { + try { + JsonObject atlasJsonObject = GsonHelper.readJsonFile(atlasesFile).getAsJsonObject(); + processAtlas(atlasJsonObject, directoryMapper::put, existingTextures::add, texturesInAtlas::add); + allAtlas.put(atlasesFile, atlasJsonObject); + } catch (IOException | JsonParseException e) { + TranslationManager.instance().log("warning.config.resource_pack.generation.malformatted_json", atlasesFile.toAbsolutePath().toString()); + } + } + List namespaces; try { namespaces = FileUtils.collectNamespaces(assetsPath); } catch (IOException e) { - plugin.logger().warn("Failed to collect namespaces for " + assetsPath.toAbsolutePath(), e); + this.plugin.logger().warn("Failed to collect namespaces for " + assetsPath.toAbsolutePath(), e); return; } - for (Path namespacePath : namespaces) { - Path atlasesFile = namespacePath.resolve("atlases").resolve("blocks.json"); - if (Files.exists(atlasesFile)) { - try { - JsonObject atlasJsonObject = GsonHelper.readJsonFile(atlasesFile).getAsJsonObject(); - 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()); - } - } + for (Path namespacePath : namespaces) { Path fontPath = namespacePath.resolve("font"); if (Files.isDirectory(fontPath)) { try { @@ -1079,6 +1083,8 @@ public abstract class AbstractPackManager implements PackManager { TranslationManager.instance().log("warning.config.resource_pack.generation.missing_block_model", entry.getValue().stream().distinct().toList().toString(), modelPath); } + Set texturesToFix = new HashSet<>(); + // 验证贴图是否存在 boolean enableObf = Config.enableObfuscation() && Config.enableRandomResourceLocation(); label: for (Map.Entry> entry : imageToModels.asMap().entrySet()) { @@ -1108,7 +1114,48 @@ public abstract class AbstractPackManager implements PackManager { continue label; } } - TranslationManager.instance().log("warning.config.resource_pack.generation.texture_not_in_atlas", key.toString()); + if (Config.fixTextureAtlas()) { + texturesToFix.add(key); + } else { + TranslationManager.instance().log("warning.config.resource_pack.generation.texture_not_in_atlas", key.toString()); + } + } + } + + if (Config.fixTextureAtlas() && !texturesToFix.isEmpty()) { + List sourcesToAdd = new ArrayList<>(); + for (Key toFix : texturesToFix) { + JsonObject source = new JsonObject(); + source.addProperty("type", "single"); + source.addProperty("resource", toFix.asString()); + sourcesToAdd.add(source); + } + + Path defaultAtlas = path.resolve("assets").resolve("minecraft").resolve("atlases").resolve("blocks.json"); + if (!allAtlas.containsKey(defaultAtlas)) { + allAtlas.put(defaultAtlas, new JsonObject()); + try { + Files.createDirectories(defaultAtlas.getParent()); + } catch (IOException e) { + this.plugin.logger().warn("could not create default atlas directory", e); + } + } + + for (Map.Entry atlas : allAtlas.entrySet()) { + JsonObject right = atlas.getValue(); + JsonArray sources = right.getAsJsonArray("sources"); + if (sources == null) { + sources = new JsonArray(); + right.add("sources", sources); + } + for (JsonObject source : sourcesToAdd) { + sources.add(source); + } + try { + GsonHelper.writeJsonFile(right, atlas.getKey()); + } catch (IOException e) { + this.plugin.logger().warn("Failed to write atlas to json file", e); + } } } } 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 1cb3d542b..8f36b8752 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 @@ -64,7 +64,8 @@ public class Config { protected boolean resource_pack$protection$crash_tools$method_2; protected boolean resource_pack$protection$crash_tools$method_3; - protected boolean resource_pack$validate$enable; + protected boolean resource_pack$validation$enable; + protected boolean resource_pack$validation$fix_atlas; protected boolean resource_pack$exclude_core_shaders; protected boolean resource_pack$protection$obfuscation$enable; @@ -296,7 +297,7 @@ public class Config { resource_pack$protection$crash_tools$method_1 = config.getBoolean("resource-pack.protection.crash-tools.method-1", false); resource_pack$protection$crash_tools$method_2 = config.getBoolean("resource-pack.protection.crash-tools.method-2", false); resource_pack$protection$crash_tools$method_3 = config.getBoolean("resource-pack.protection.crash-tools.method-3", false); - resource_pack$protection$obfuscation$enable = config.getBoolean("resource-pack.protection.obfuscation.enable", false); + resource_pack$protection$obfuscation$enable = VersionHelper.PREMIUM && config.getBoolean("resource-pack.protection.obfuscation.enable", false); resource_pack$protection$obfuscation$seed = config.getLong("resource-pack.protection.obfuscation.seed", 0L); resource_pack$protection$obfuscation$fake_directory = config.getBoolean("resource-pack.protection.obfuscation.fake-directory", false); resource_pack$protection$obfuscation$escape_unicode = config.getBoolean("resource-pack.protection.obfuscation.escape-unicode", false); @@ -313,7 +314,8 @@ public class Config { resource_pack$protection$obfuscation$resource_location$bypass_models = config.getStringList("resource-pack.protection.obfuscation.resource-location.bypass-models"); resource_pack$protection$obfuscation$resource_location$bypass_sounds = config.getStringList("resource-pack.protection.obfuscation.resource-location.bypass-sounds"); resource_pack$protection$obfuscation$resource_location$bypass_equipments = config.getStringList("resource-pack.protection.obfuscation.resource-location.bypass-equipments"); - resource_pack$validate$enable = config.getBoolean("resource-pack.validate.enable", true); + resource_pack$validation$enable = config.getBoolean("resource-pack.validation.enable", true); + resource_pack$validation$fix_atlas = VersionHelper.PREMIUM && config.getBoolean("resource-pack.validation.fix-atlas", true); resource_pack$exclude_core_shaders = config.getBoolean("resource-pack.exclude-core-shaders", false); resource_pack$overlay_format = config.getString("resource-pack.overlay-format", "overlay_{version}"); if (!resource_pack$overlay_format.contains("{version}")) { @@ -895,7 +897,11 @@ public class Config { } public static boolean validateResourcePack() { - return instance.resource_pack$validate$enable; + return instance.resource_pack$validation$enable; + } + + public static boolean fixTextureAtlas() { + return instance.resource_pack$validation$fix_atlas; } public static boolean excludeShaders() { diff --git a/gradle.properties b/gradle.properties index c3f2fe021..94725baf0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] project_version=0.0.63.7 -config_version=46 +config_version=47 lang_version=31 project_group=net.momirealms latest_supported_version=1.21.8 From 4cca5288e4b3c513cc5459784b794a106f84d13e Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sun, 28 Sep 2025 21:31:30 +0800 Subject: [PATCH 080/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8E=9F=E7=89=88?= =?UTF-8?q?=E6=96=B9=E5=9D=97=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../item/behavior/FurnitureItemBehavior.java | 5 ++-- .../core/block/AbstractBlockManager.java | 2 +- .../furniture/AbstractFurnitureManager.java | 25 ++++++++++++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) 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 82a1f8457..83b4bdef6 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 @@ -20,6 +20,7 @@ import net.momirealms.craftengine.core.item.behavior.ItemBehavior; import net.momirealms.craftengine.core.item.behavior.ItemBehaviorFactory; import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; @@ -185,9 +186,9 @@ public class FurnitureItemBehavior extends ItemBehavior { if (id instanceof Map map) { if (map.containsKey(key.toString())) { // 防呆 - BukkitFurnitureManager.instance().parser().parseSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false)); + BukkitFurnitureManager.instance().parser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, MiscUtils.castToMap(map.get(key.toString()), false))); } else { - BukkitFurnitureManager.instance().parser().parseSection(pack, path, node, key, MiscUtils.castToMap(map, false)); + BukkitFurnitureManager.instance().parser().addPendingConfigSection(new PendingConfigSection(pack, path, node, key, MiscUtils.castToMap(map, false))); } return new FurnitureItemBehavior(key); } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 94740912f..206feef2d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -253,7 +253,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem String after = entry.getValue().toString(); // 先解析为唯一的wrapper BlockStateWrapper beforeState = createVanillaBlockState(before); - BlockStateWrapper afterState = createVanillaBlockState(before); + BlockStateWrapper afterState = createVanillaBlockState(after); if (beforeState == null) { exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block_state_mapping.invalid_state", before)); continue; 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 0d5a714d9..d99d43e8b 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 @@ -1,20 +1,25 @@ package net.momirealms.craftengine.core.entity.furniture; +import net.momirealms.craftengine.core.block.AbstractBlockManager; import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.loot.LootTable; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; +import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.incendo.cloud.suggestion.Suggestion; import org.joml.Vector3f; +import java.io.IOException; import java.nio.file.Path; import java.util.*; @@ -31,7 +36,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { } @Override - public IdSectionConfigParser parser() { + public FurnitureParser parser() { return this.furnitureParser; } @@ -76,6 +81,24 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { public class FurnitureParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; + private final List pendingConfigSections = new ArrayList<>(); + + public void addPendingConfigSection(PendingConfigSection section) { + this.pendingConfigSections.add(section); + } + + @Override + public void preProcess() { + for (PendingConfigSection section : this.pendingConfigSections) { + ResourceConfigUtils.runCatching( + section.path(), + section.node(), + () -> parseSection(section.pack(), section.path(), section.node(), section.id(), section.config()), + () -> GsonHelper.get().toJson(section.config()) + ); + } + this.pendingConfigSections.clear(); + } @Override public String[] sectionId() { From 7d24430a40a2637db8ade878d0d5ece34d96d770 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sun, 28 Sep 2025 21:35:52 +0800 Subject: [PATCH 081/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dcrafting=20ui?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/plugin/gui/BukkitGuiManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java index fb01ccc33..dbf750e06 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java @@ -55,7 +55,7 @@ public class BukkitGuiManager implements GuiManager, Listener { case ANVIL -> MenuType.ANVIL.create(bukkitPlayer).open(); case LOOM -> MenuType.LOOM.create(bukkitPlayer).open(); case ENCHANTMENT -> MenuType.ENCHANTMENT.create(bukkitPlayer).open(); - case CRAFTING -> MenuType.CRAFTER_3X3.create(bukkitPlayer).open(); + case CRAFTING -> MenuType.CRAFTING.create(bukkitPlayer).open(); case CARTOGRAPHY -> MenuType.CARTOGRAPHY_TABLE.create(bukkitPlayer).open(); case SMITHING -> MenuType.SMITHING.create(bukkitPlayer).open(); case GRINDSTONE -> MenuType.GRINDSTONE.create(bukkitPlayer).open(); From 5c06d8af13e4af9b377f6236b00f7eaa7db5afc7 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 29 Sep 2025 00:26:57 +0800 Subject: [PATCH 082/125] =?UTF-8?q?=E5=AD=97=E4=BD=93=E5=AD=97=E7=AC=A6id?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mythicmobs/MythicItemDrop.java | 4 +- .../bukkit/block/BukkitBlockManager.java | 2 +- .../behavior/SimpleStorageBlockBehavior.java | 6 +- .../furniture/hitbox/ShulkerHitBox.java | 2 +- .../item/listener/DebugStickListener.java | 3 +- .../item/listener/ItemEventListener.java | 4 +- .../bukkit/plugin/gui/BukkitGuiManager.java | 31 +- .../handler/ProjectilePacketHandler.java | 12 +- common-files/src/main/resources/config.yml | 9 +- .../resources/default/configuration/emoji.yml | 6 +- .../resources/internal/configuration/gui.yml | 12 - .../internal/configuration/offset_chars.yml | 88 +++--- .../src/main/resources/translations/de.yml | 4 +- .../src/main/resources/translations/en.yml | 8 +- .../src/main/resources/translations/es.yml | 2 +- .../src/main/resources/translations/ru_ru.yml | 4 +- .../src/main/resources/translations/tr.yml | 2 +- .../src/main/resources/translations/zh_cn.yml | 5 +- .../core/block/AbstractBlockManager.java | 2 +- .../furniture/AbstractFurnitureManager.java | 3 - .../core/font/AbstractFontManager.java | 262 +++++++++++----- .../core/item/AbstractItemManager.java | 2 +- .../craftengine/core/loot/LootPool.java | 4 +- .../entry/AbstractLootEntryContainer.java | 4 +- .../AbstractLootConditionalFunction.java | 4 +- .../core/pack/AbstractPackManager.java | 3 + .../core/plugin/config/Config.java | 28 +- .../context/condition/AllOfCondition.java | 3 +- .../context/condition/AnyOfCondition.java | 3 +- .../function/AbstractConditionalFunction.java | 3 +- .../context/function/BreakBlockFunction.java | 4 +- .../context/function/PlaceBlockFunction.java | 4 +- .../plugin/context/function/RunFunction.java | 4 +- .../number/GaussianNumberProvider.java | 4 +- .../parameter/EntityParameterProvider.java | 8 +- .../parameter/PlayerParameterProvider.java | 8 +- .../parameter/PositionParameterProvider.java | 8 +- .../context/selector/AllPlayerSelector.java | 4 +- .../plugin/network/codec/NetworkCodecs.java | 4 +- .../core/registry/ConstantBoundRegistry.java | 4 +- .../craftengine/core/util/CharacterUtils.java | 3 +- .../craftengine/core/util/Color.java | 2 +- .../craftengine/core/util/Direction.java | 8 +- .../core/util/FriendlyByteBuf.java | 8 +- .../core/util/Int2ObjectBiMap.java | 2 +- .../craftengine/core/util/MCUtils.java | 294 ------------------ .../craftengine/core/util/MiscUtils.java | 294 +++++++++++++++++- .../core/util/QuaternionUtils.java | 12 +- .../craftengine/core/world/BlockPos.java | 4 +- .../core/world/EntityHitResult.java | 8 +- .../craftengine/core/world/Vec3d.java | 4 +- .../core/world/chunk/PalettedContainer.java | 8 +- gradle.properties | 26 +- 53 files changed, 676 insertions(+), 574 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java index dbb2f00db..9258e4214 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/mythicmobs/MythicItemDrop.java @@ -13,7 +13,7 @@ import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -42,7 +42,7 @@ public class MythicItemDrop extends ItemDrop implements IItemDrop { context = ItemBuildContext.of(player); } } - int amountInt = MCUtils.fastFloor(amount + 0.5F); + int amountInt = MiscUtils.fastFloor(amount + 0.5F); ItemStack itemStack = this.customItem.buildItemStack(context, amountInt); return adapt(itemStack).amount(amountInt); } 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 acc7ee28e..705ef4dd4 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 @@ -362,7 +362,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { // 注册服务端侧的真实方块 private void registerServerSideCustomBlocks(int count) { // 这个会影响全局调色盘 - if (MCUtils.ceilLog2(this.vanillaBlockStateCount + count) == MCUtils.ceilLog2(this.vanillaBlockStateCount)) { + if (MiscUtils.ceilLog2(this.vanillaBlockStateCount + count) == MiscUtils.ceilLog2(this.vanillaBlockStateCount)) { PalettedContainer.NEED_DOWNGRADE = false; } try { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleStorageBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleStorageBlockBehavior.java index 0a7933cad..07b33233f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleStorageBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SimpleStorageBlockBehavior.java @@ -20,7 +20,7 @@ import net.momirealms.craftengine.core.item.context.UseOnContext; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.AdventureHelper; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.CEWorld; @@ -166,7 +166,7 @@ public class SimpleStorageBlockBehavior extends BukkitBlockBehavior implements E } } signal /= (float) inventory.getSize(); - return MCUtils.lerpDiscrete(signal, 0, 15); + return MiscUtils.lerpDiscrete(signal, 0, 15); } } return 0; @@ -194,7 +194,7 @@ public class SimpleStorageBlockBehavior extends BukkitBlockBehavior implements E @Override public BlockBehavior create(CustomBlock block, Map arguments) { String title = arguments.getOrDefault("title", "").toString(); - int rows = MCUtils.clamp(ResourceConfigUtils.getAsInt(arguments.getOrDefault("rows", 1), "rows"), 1, 6); + int rows = MiscUtils.clamp(ResourceConfigUtils.getAsInt(arguments.getOrDefault("rows", 1), "rows"), 1, 6); Map sounds = (Map) arguments.get("sounds"); boolean hasAnalogOutputSignal = ResourceConfigUtils.getAsBoolean(arguments.getOrDefault("has-signal", true), "has-signal"); SoundData openSound = null; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java index 5f72065db..9883004cc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/furniture/hitbox/ShulkerHitBox.java @@ -171,7 +171,7 @@ public class ShulkerHitBox extends AbstractHitBox { } private static float getPhysicalPeek(float peek) { - return 0.5F - MCUtils.sin((0.5F + peek) * 3.1415927F) * 0.5F; + return 0.5F - MiscUtils.sin((0.5F + peek) * 3.1415927F) * 0.5F; } public boolean interactionEntity() { 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 8b8df50b4..b3f763ce1 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 @@ -17,7 +17,6 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.MiscUtils; import org.bukkit.Material; import org.bukkit.block.Block; @@ -119,7 +118,7 @@ public class DebugStickListener implements Listener { } private static T getRelative(Iterable elements, @Nullable T current, boolean inverse) { - return inverse ? MCUtils.findPreviousInIterable(elements, current) : MCUtils.findNextInIterable(elements, current); + return inverse ? MiscUtils.findPreviousInIterable(elements, current) : MiscUtils.findNextInIterable(elements, current); } private static > String getNameHelper(ImmutableBlockState state, Property property) { 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 2dc58f76d..9038391e2 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 @@ -474,9 +474,9 @@ public class ItemEventListener implements Listener { if (foodData == null) return; event.setCancelled(true); int oldFoodLevel = player.getFoodLevel(); - if (foodData.nutrition() != 0) player.setFoodLevel(MCUtils.clamp(oldFoodLevel + foodData.nutrition(), 0, 20)); + if (foodData.nutrition() != 0) player.setFoodLevel(MiscUtils.clamp(oldFoodLevel + foodData.nutrition(), 0, 20)); float oldSaturation = player.getSaturation(); - if (foodData.saturation() != 0) player.setSaturation(MCUtils.clamp(oldSaturation, 0, 10)); + if (foodData.saturation() != 0) player.setSaturation(MiscUtils.clamp(oldSaturation, 0, 10)); } private boolean cancelEventIfHasInteraction(PlayerInteractEvent event, BukkitServerPlayer player, InteractionHand hand) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java index dbf750e06..65feeb73d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/gui/BukkitGuiManager.java @@ -12,7 +12,6 @@ import net.momirealms.craftengine.bukkit.util.InventoryUtils; import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.gui.*; -import net.momirealms.craftengine.core.util.ReflectionUtils; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -23,11 +22,9 @@ import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.inventory.InventoryView; -import org.bukkit.inventory.MenuType; public class BukkitGuiManager implements GuiManager, Listener { - private static final boolean useNewOpenInventory = ReflectionUtils.getDeclaredMethod(InventoryView.class, void.class, new String[]{"open"}) != null; +// private static final boolean useNewOpenInventory = ReflectionUtils.getDeclaredMethod(InventoryView.class, void.class, new String[]{"open"}) != null; private static BukkitGuiManager instance; private final BukkitCraftEngine plugin; @@ -46,21 +43,21 @@ public class BukkitGuiManager implements GuiManager, Listener { HandlerList.unregisterAll(this); } - @SuppressWarnings("UnstableApiUsage") +// @SuppressWarnings("UnstableApiUsage") @Override public void openInventory(net.momirealms.craftengine.core.entity.player.Player player, GuiType guiType) { Player bukkitPlayer = (Player) player.platformPlayer(); - if (useNewOpenInventory) { - switch (guiType) { - case ANVIL -> MenuType.ANVIL.create(bukkitPlayer).open(); - case LOOM -> MenuType.LOOM.create(bukkitPlayer).open(); - case ENCHANTMENT -> MenuType.ENCHANTMENT.create(bukkitPlayer).open(); - case CRAFTING -> MenuType.CRAFTING.create(bukkitPlayer).open(); - case CARTOGRAPHY -> MenuType.CARTOGRAPHY_TABLE.create(bukkitPlayer).open(); - case SMITHING -> MenuType.SMITHING.create(bukkitPlayer).open(); - case GRINDSTONE -> MenuType.GRINDSTONE.create(bukkitPlayer).open(); - } - } else { +// if (useNewOpenInventory) { +// switch (guiType) { +// case ANVIL -> MenuType.ANVIL.create(bukkitPlayer).open(); +// case LOOM -> MenuType.LOOM.create(bukkitPlayer).open(); +// case ENCHANTMENT -> MenuType.ENCHANTMENT.create(bukkitPlayer).open(); +// case CRAFTING -> MenuType.CRAFTING.create(bukkitPlayer).open(); +// case CARTOGRAPHY -> MenuType.CARTOGRAPHY_TABLE.create(bukkitPlayer).open(); +// case SMITHING -> MenuType.SMITHING.create(bukkitPlayer).open(); +// case GRINDSTONE -> MenuType.GRINDSTONE.create(bukkitPlayer).open(); +// } +// } else { switch (guiType) { case ANVIL -> LegacyInventoryUtils.openAnvil(bukkitPlayer); case LOOM -> LegacyInventoryUtils.openLoom(bukkitPlayer); @@ -70,7 +67,7 @@ public class BukkitGuiManager implements GuiManager, Listener { case ENCHANTMENT -> LegacyInventoryUtils.openEnchanting(bukkitPlayer); case CARTOGRAPHY -> LegacyInventoryUtils.openCartographyTable(bukkitPlayer); } - } +// } } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java index 1524c7a39..a85925165 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/ProjectilePacketHandler.java @@ -16,7 +16,7 @@ import net.momirealms.craftengine.core.plugin.network.EntityPacketHandler; import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent; import net.momirealms.craftengine.core.plugin.network.NetWorkUser; import net.momirealms.craftengine.core.util.FriendlyByteBuf; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.Vec3d; import org.bukkit.inventory.ItemStack; @@ -89,8 +89,8 @@ public class ProjectilePacketHandler implements EntityPacketHandler { buf.writeDouble(y); buf.writeDouble(z); if (VersionHelper.isOrAbove1_21_9()) buf.writeLpVec3(movement); - buf.writeByte(MCUtils.packDegrees(MCUtils.clamp(-MCUtils.unpackDegrees(xRot), -90.0F, 90.0F))); - buf.writeByte(MCUtils.packDegrees(-MCUtils.unpackDegrees(yRot))); + buf.writeByte(MiscUtils.packDegrees(MiscUtils.clamp(-MiscUtils.unpackDegrees(xRot), -90.0F, 90.0F))); + buf.writeByte(MiscUtils.packDegrees(-MiscUtils.unpackDegrees(yRot))); buf.writeByte(yHeadRot); buf.writeVarInt(data); if (!VersionHelper.isOrAbove1_21_9()) buf.writeShort(xa); @@ -142,12 +142,12 @@ public class ProjectilePacketHandler implements EntityPacketHandler { short xa = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xa(packet); short ya = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$ya(packet); short za = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$za(packet); - float xRot = MCUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xRot(packet)); - float yRot = MCUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$yRot(packet)); + float xRot = MiscUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$xRot(packet)); + float yRot = MiscUtils.unpackDegrees(FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$yRot(packet)); boolean onGround = FastNMS.INSTANCE.field$ClientboundMoveEntityPacket$onGround(packet); return FastNMS.INSTANCE.constructor$ClientboundMoveEntityPacket$PosRot( entityId, xa, ya, za, - MCUtils.packDegrees(-yRot), MCUtils.packDegrees(MCUtils.clamp(-xRot, -90.0F, 90.0F)), + MiscUtils.packDegrees(-yRot), MiscUtils.packDegrees(MiscUtils.clamp(-xRot, -90.0F, 90.0F)), onGround ); } diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 3203ee842..a96c789c1 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -175,7 +175,7 @@ equipment: block: # This decides the amount of real blocks on serverside. Requires a restart to apply. - serverside-blocks: 2000 + serverside-blocks: 2025 # Enables the sound system, which prevents the client from hearing some non-custom block sounds and improves the client experience. sound-system: enable: true @@ -232,12 +232,17 @@ image: chat: true command: true sign: true + # Decided the starting value for automatic codepoint assignment. + codepoint-starting-value: + default: 19968 + overrides: + minecraft:default: 57344 # 57344 ~ 63743 (U+E000 ~ U+F8FF) # Defines Unicode characters used for positioning # - Must match the font defined in resource packs # - Do NOT modify unless you understand text rendering mechanics offset-characters: - font: minecraft:offset_chars + font: minecraft:default -1: '\uf800' -2: '\uf801' -3: '\uf802' diff --git a/common-files/src/main/resources/resources/default/configuration/emoji.yml b/common-files/src/main/resources/resources/default/configuration/emoji.yml index 49c0ca5c6..06262afd2 100644 --- a/common-files/src/main/resources/resources/default/configuration/emoji.yml +++ b/common-files/src/main/resources/resources/default/configuration/emoji.yml @@ -122,8 +122,4 @@ images: ascent: 9 font: minecraft:emoji file: minecraft:font/image/emojis.png - chars: - - \ub000\ub001\ub002\ub003 - - \ub004\ub005\ub006\ub007 - - \ub008\ub009\ub00a\ub00b - - \ub00c\ub00d\ub00e\ub00f \ No newline at end of file + grid-size: 4,4 \ No newline at end of file diff --git a/common-files/src/main/resources/resources/internal/configuration/gui.yml b/common-files/src/main/resources/resources/internal/configuration/gui.yml index 344d37d55..87efc97c5 100644 --- a/common-files/src/main/resources/resources/internal/configuration/gui.yml +++ b/common-files/src/main/resources/resources/internal/configuration/gui.yml @@ -4,73 +4,61 @@ images: ascent: 18 font: minecraft:gui file: minecraft:font/gui/custom/item_browser.png - char: \ub000 internal:category: height: 140 ascent: 18 font: minecraft:gui file: minecraft:font/gui/custom/category.png - char: \ub001 internal:crafting_recipe: height: 142 ascent: 20 font: minecraft:gui file: minecraft:font/gui/custom/crafting_recipe.png - char: \ub002 internal:cooking_recipe: height: 138 ascent: 16 font: minecraft:gui file: minecraft:font/gui/custom/cooking_recipe.png - char: \ub003 internal:smelting: height: 23 ascent: 20 font: minecraft:gui file: minecraft:font/gui/custom/smelting.png - char: \ub004 internal:smoking: height: 23 ascent: 20 font: minecraft:gui file: minecraft:font/gui/custom/smoking.png - char: \ub005 internal:blasting: height: 23 ascent: 20 font: minecraft:gui file: minecraft:font/gui/custom/blasting.png - char: \ub006 internal:campfire: height: 23 ascent: 20 font: minecraft:gui file: minecraft:font/gui/custom/campfire.png - char: \ub007 internal:stonecutting_recipe: height: 142 ascent: 20 font: minecraft:gui file: minecraft:font/gui/custom/stonecutting_recipe.png - char: \ub008 internal:smithing_transform_recipe: height: 142 ascent: 20 font: minecraft:gui file: minecraft:font/gui/custom/smithing_transform_recipe.png - char: \ub009 internal:brewing_recipe: height: 142 ascent: 20 font: minecraft:gui file: minecraft:font/gui/custom/brewing_recipe.png - char: \ub00a internal:no_recipe: height: 140 ascent: 18 font: minecraft:gui file: minecraft:font/gui/custom/no_recipe.png - char: \ub00b templates: internal:icon/2d: material: arrow diff --git a/common-files/src/main/resources/resources/internal/configuration/offset_chars.yml b/common-files/src/main/resources/resources/internal/configuration/offset_chars.yml index f315f2571..4857eb238 100644 --- a/common-files/src/main/resources/resources/internal/configuration/offset_chars.yml +++ b/common-files/src/main/resources/resources/internal/configuration/offset_chars.yml @@ -2,264 +2,264 @@ images: internal:neg_1: height: -3 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf800 internal:neg_2: height: -4 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf801 internal:neg_3: height: -5 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf802 internal:neg_4: height: -6 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf803 internal:neg_5: height: -7 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf804 internal:neg_6: height: -8 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf805 internal:neg_7: height: -9 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf806 internal:neg_8: height: -10 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf807 internal:neg_9: height: -11 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf808 internal:neg_10: height: -12 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf809 internal:neg_11: height: -13 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf80a internal:neg_12: height: -14 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf80b internal:neg_13: height: -15 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf80c internal:neg_14: height: -16 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf80d internal:neg_15: height: -17 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf80e internal:neg_16: height: -18 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf80f internal:neg_24: height: -26 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf810 internal:neg_32: height: -34 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf811 internal:neg_48: height: -50 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf812 internal:neg_64: height: -66 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf813 internal:neg_128: height: -130 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf814 internal:neg_256: height: -258 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf815 internal:pos_1: height: -1 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf830 internal:pos_2: height: 1 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf831 internal:pos_3: height: 2 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf832 internal:pos_4: height: 3 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf833 internal:pos_5: height: 4 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf834 internal:pos_6: height: 5 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf835 internal:pos_7: height: 6 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf836 internal:pos_8: height: 7 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf837 internal:pos_9: height: 8 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf838 internal:pos_10: height: 9 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf839 internal:pos_11: height: 10 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf83a internal:pos_12: height: 11 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf83b internal:pos_13: height: 12 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf83c internal:pos_14: height: 13 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf83d internal:pos_15: height: 14 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf83e internal:pos_16: height: 15 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf83f internal:pos_24: height: 23 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf840 internal:pos_32: height: 31 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf841 internal:pos_48: height: 47 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf842 internal:pos_64: height: 63 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf843 internal:pos_128: height: 127 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf844 internal:pos_256: height: 255 ascent: -5000 - font: minecraft:offset_chars + font: minecraft:default file: minecraft:font/offset/space_split.png char: \uf845 \ No newline at end of file diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index a02740112..3d10d877e 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -115,7 +115,7 @@ warning.config.image.missing_file: "Problem in Datei gefunden - warning.config.image.invalid_file_chars: "Problem in Datei gefunden - Das Image '' hat ein 'file'-Argument '', das ungültige Zeichen enthält. Bitte lies https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.image.invalid_font_chars: "Problem in Datei gefunden - Das Image '' hat ein 'font'-Argument '', das ungültige Zeichen enthält. Bitte lies https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.image.missing_char: "Problem in Datei gefunden - Beim Image '' fehlt das erforderliche 'char'-Argument." -warning.config.image.codepoint_conflict: "Problem in Datei gefunden - Das Image '' verwendet ein Zeichen '()' im Font , das bereits von einem anderen Image '' verwendet wird." +warning.config.image.codepoint.conflict: "Problem in Datei gefunden - Das Image '' verwendet ein Zeichen '()' im Font , das bereits von einem anderen Image '' verwendet wird." warning.config.image.invalid_codepoint_grid: "Problem in Datei gefunden - Image '' hat ein ungültiges 'chars' Codepoint-Grid." warning.config.image.invalid_char: "Problem in Datei gefunden - Image '' hat einen char-Parameter, der kombinierende Zeichen enthält, was zur Aufteilung des Bildes führen kann." warning.config.image.invalid_hex_value: "Problem in Datei gefunden - Das Image '' verwendet ein Unicode-Zeichen '', das kein gültiger hexadezimaler (Basis 16) Wert ist." @@ -407,7 +407,7 @@ warning.config.selector.invalid_target: "Problem in Datei gefund warning.config.resource_pack.item_model.already_exist: "Generierung des Item-Models für '' fehlgeschlagen, da die Datei '' bereits existiert." warning.config.resource_pack.model.generation.already_exist: "Generierung des Models fehlgeschlagen, da die Model-Datei '' bereits existiert." warning.config.resource_pack.generation.missing_font_texture: "Beim Font '' fehlt die erforderliche Textur: ''" -warning.config.resource_pack.generation.texture_not_in_atlas: "Textur '' ist nicht im Atlas aufgeführt. Du musst den Texturpfad zum Atlas hinzufügen oder die 'obfuscation'-Option in der config.yml aktivieren." +warning.config.resource_pack.generation.texture_not_in_atlas: "Textur '' ist nicht im Atlas aufgeführt. Du musst den Texturpfad zum Atlas hinzufügen oder die 'obfuscation'/'fix-atlas'-Option in der config.yml aktivieren." warning.config.resource_pack.generation.missing_model_texture: "Beim Model '' fehlt die Textur ''" warning.config.resource_pack.generation.missing_item_model: "Beim Item '' fehlt die Model-Datei: ''" warning.config.resource_pack.generation.missing_block_model: "Beim Block-State '' fehlt die Model-Datei: ''" diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index e15c5f89d..a9cf1ec13 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -122,8 +122,10 @@ warning.config.image.height_ascent_conflict: "Issue found in file Issue found in file - The image '' is missing the required 'file' argument." warning.config.image.invalid_file_chars: "Issue found in file - The image '' has a 'file' argument '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." warning.config.image.invalid_font_chars: "Issue found in file - The image '' has a 'font' argument '' that contains illegal characters. Please read https://minecraft.wiki/w/Resource_location#Legal_characters." +warning.config.image.invalid_grid_size: "Issue found in file - The image '' is using an incorrect grid size format ''. Correct example: '3,5'" warning.config.image.missing_char: "Issue found in file - The image '' is missing the required 'char' argument." -warning.config.image.codepoint_conflict: "Issue found in file - The image '' is using a character '()' in font that has been used by another image ''." +warning.config.image.codepoint.conflict: "Issue found in file - The image '' is using a character '()' in font that has been used by another image ''." +warning.config.image.codepoint.exhausted: "Issue found in file - Cannot allocate codepoint for image '' as the codepoints have already been exhausted for font ''." warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grid." warning.config.image.invalid_char: "Issue found in file - Image '' has a char parameter containing combining characters, which may result in image splitting." warning.config.image.invalid_hex_value: "Issue found in file - The image '' is using a unicode character '' that is not a valid hexadecimal (radix 16) value." @@ -193,7 +195,7 @@ warning.config.item.invalid_custom_model_data: "Issue found in file 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.custom_model_data.exhausted: "Issue found in file - Cannot allocate custom model data for item '' as the custom model data has already been exhausted." +warning.config.item.custom_model_data.exhausted: "Issue found in file - Cannot allocate custom model data for item '' as the custom model data has already been exhausted for material ''." warning.config.item.invalid_component: "Issue found in file - The item '' is using a non-existing component type ''." warning.config.item.missing_model_id: "Issue found in file - The item '' is missing the required 'custom-model-data' or 'item-model' argument." warning.config.item.missing_model: "Issue found in file - The item '' is missing the required 'model' section for 1.21.4+ resource pack support." @@ -461,7 +463,7 @@ warning.config.resource_pack.generation.missing_item_model: "Item 'Block state '' is missing model file: ''" warning.config.resource_pack.generation.missing_parent_model: "Model '' cannot find parent model: ''" warning.config.resource_pack.generation.missing_equipment_texture: "Equipment '' is missing 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.texture_not_in_atlas: "Texture '' is not listed in the atlas. You need to add the texture path to the atlas or enable 'obfuscation' or 'fix-atlas' option in config.yml." 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." diff --git a/common-files/src/main/resources/translations/es.yml b/common-files/src/main/resources/translations/es.yml index eaa30b979..908d1752c 100644 --- a/common-files/src/main/resources/translations/es.yml +++ b/common-files/src/main/resources/translations/es.yml @@ -77,7 +77,7 @@ warning.config.image.missing_file: "Problema encontrado en el archivo Problema encontrado en el archivo - La imagen '' tiene un argumento 'file' '' que contiene caracteres prohibidos. Por favor lee https://minecraft.wiki/w/Resource_location#Legal_characters" warning.config.image.invalid_font_chars: "Problema encontrado en el archivo - La imagen '' tiene un argumento 'font' '' que contiene caracteres prohibidos. Por favor lee https://minecraft.wiki/w/Resource_location#Legal_characters" warning.config.image.missing_char: "Problema encontrado en el archivo - La imagen '' carece del argumento requerido 'char'." -warning.config.image.codepoint_conflict: "Problema encontrado en el archivo - La imagen '' está usando el carácter '()' que ya ha sido usado por otra imagen '' en la fuente ." +warning.config.image.codepoint.conflict: "Problema encontrado en el archivo - La imagen '' está usando el carácter '()' que ya ha sido usado por otra imagen '' en la fuente ." warning.config.image.invalid_codepoint_grid: "Problema encontrado en el archivo - La imagen '' tiene una cuadrícula de puntos de código 'chars' inválida." warning.config.image.file_not_found: "Problema encontrado en el archivo - Archivo PNG '' no encontrado para la imagen ''." warning.config.image.invalid_hex_value: "Problema encontrado en el archivo - La imagen '' está usando el carácter unicode '' que no es un valor hexadecimal válido." diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml index e3d30278c..baf7bc52c 100644 --- a/common-files/src/main/resources/translations/ru_ru.yml +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -113,7 +113,7 @@ warning.config.image.missing_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.codepoint.conflict: "Проблема найдена в файле - Изображение '' использует символ '()' в шрифте который был использован другим изображением ''." warning.config.image.invalid_codepoint_grid: "Проблема найдена в файле - Изображение '' имеет недействительную 'chars' сетку кодовых точек." warning.config.image.invalid_char: "Проблема найдена в файле - Изображение '' имеет параметр char, содержащий комбинированные символы, что может привести к разделению изображения." warning.config.image.invalid_hex_value: "Проблема найдена в файле - Изображение '' использует символ юникода '' это недопустимое шестнадцатеричное (radix 16) значение." @@ -376,7 +376,7 @@ 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.texture_not_in_atlas: "Текстура '' не указана в атласе. Вам нужно добавить путь к текстуре в атлас или включить 'obfuscation'/'fix-atlas' опцию в 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: "В блоке '' отсутствует файл модели: ''" diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index b62967f92..20538d70e 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -77,7 +77,7 @@ warning.config.image.missing_file: " dosyasında sorun bulundu - warning.config.image.invalid_file_chars: " dosyasında sorun bulundu - '' resmi, yasak karakterler içeren '' 'file' argümanına sahip. Lütfen https://minecraft.wiki/w/Resource_location#Legal_characters sayfasını okuyun." warning.config.image.invalid_font_chars: " dosyasında sorun bulundu - '' resmi, yasak karakterler içeren '' 'font' argümanına sahip. Lütfen https://minecraft.wiki/w/Resource_location#Legal_characters sayfasını okuyun." warning.config.image.missing_char: " dosyasında sorun bulundu - '' resmi gerekli 'char' argümanı eksik." -warning.config.image.codepoint_conflict: " dosyasında sorun bulundu - '' resmi, yazı tipinde başka bir resim '' tarafından kullanılmış olan '()' karakterini kullanıyor." +warning.config.image.codepoint.conflict: " dosyasında sorun bulundu - '' resmi, yazı tipinde başka bir resim '' tarafından kullanılmış olan '()' karakterini kullanıyor." warning.config.image.invalid_codepoint_grid: " dosyasında sorun bulundu - '' resminin geçersiz bir 'chars' kod noktası ızgarası var." warning.config.image.invalid_hex_value: " dosyasında sorun bulundu - '' resmi, geçerli bir onaltılık (16 tabanlı) değer olmayan '' unicode karakterini kullanıyor." warning.config.recipe.duplicate: " dosyasında sorun bulundu - Yinelenen tarif ''. Diğer dosyalarda aynı yapılandırmanın olup olmadığını kontrol edin." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 9d0175d00..21e1bae3b 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -122,8 +122,9 @@ warning.config.image.height_ascent_conflict: "在文件 发现 warning.config.image.missing_file: "在文件 发现问题 - 图片 '' 缺少必需的 'file' 参数" warning.config.image.invalid_file_chars: "在文件 发现问题 - 图片 '' 的 'file' 参数 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" warning.config.image.invalid_font_chars: "在文件 发现问题 - 图片 '' 的 'font' 参数 '' 包含非法字符 请参考 https://zh.minecraft.wiki/w/%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4ID#%E5%90%88%E6%B3%95%E5%AD%97%E7%AC%A6" +warning.config.image.invalid_grid_size: "在文件 发现问题 - 图片 '' 使用了无效的网格尺寸 ''. 正确的格式 '3,5'" warning.config.image.missing_char: "在文件 发现问题 - 图片 '' 缺少必需的 'char' 参数" -warning.config.image.codepoint_conflict: "在文件 发现问题 - 图片 '' 在字体 中使用的字符 '()' 已被其他图片 '' 占用" +warning.config.image.codepoint.conflict: "在文件 发现问题 - 图片 '' 在字体 中使用的字符 '()' 已被其他图片 '' 占用" warning.config.image.invalid_codepoint_grid: "在文件 发现问题 - 图片 '' 的 'chars' 码位网格无效" warning.config.image.invalid_char: "在文件 发现问题 - 图片 '' 的 'char' 参数包含组合字符可能导致图片分裂" warning.config.image.invalid_hex_value: "在文件 发现问题 - 图片 '' 使用的 Unicode 字符 '' 不是有效的十六进制值" @@ -443,7 +444,7 @@ warning.config.resource_pack.generation.missing_item_model: "物品'方块状态''缺少模型文件: ''" warning.config.resource_pack.generation.missing_parent_model: "模型''找不到父级模型文件: ''" warning.config.resource_pack.generation.missing_equipment_texture: "装备 '' 缺少纹理 ''" -warning.config.resource_pack.generation.texture_not_in_atlas: "纹理''不在图集内. 你需要将纹理路径或文件夹前缀添加到图集内,或者启用 config.yml 中的 'obfuscation' 选项" +warning.config.resource_pack.generation.texture_not_in_atlas: "纹理''不在图集内. 你需要将纹理路径或文件夹前缀添加到图集内,或者启用 config.yml 中的 'obfuscation'/'fix-atlas' 或 'fix-atlas' 选项" 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' 参数" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 206feef2d..13078a68a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -442,7 +442,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return; } } catch (InterruptedException e) { - AbstractBlockManager.this.plugin.logger().warn("Interrupted while parsing allocating internal block state", e); + AbstractBlockManager.this.plugin.logger().warn("Interrupted while allocating internal block state for block " + id.asString(), e); return; } } 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 d99d43e8b..008d83b52 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 @@ -1,6 +1,5 @@ package net.momirealms.craftengine.core.entity.furniture; -import net.momirealms.craftengine.core.block.AbstractBlockManager; import net.momirealms.craftengine.core.entity.Billboard; import net.momirealms.craftengine.core.entity.ItemDisplayContext; import net.momirealms.craftengine.core.loot.LootTable; @@ -8,7 +7,6 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.context.event.EventFunctions; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -19,7 +17,6 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import org.incendo.cloud.suggestion.Suggestion; import org.joml.Vector3f; -import java.io.IOException; import java.nio.file.Path; import java.util.*; diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 89721f922..37b33b51b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -2,10 +2,13 @@ package net.momirealms.craftengine.core.font; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.entity.player.Player; +import net.momirealms.craftengine.core.item.AbstractItemManager; 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.cache.IdAllocator; 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.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; @@ -24,6 +27,8 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -54,6 +59,14 @@ public abstract class AbstractFontManager implements FontManager { this.emojiParser = new EmojiParser(); } + public ImageParser imageParser() { + return imageParser; + } + + public EmojiParser emojiParser() { + return emojiParser; + } + @Override public void load() { this.offsetFont = Optional.ofNullable(plugin.config().settings().getSection("image.offset-characters")) @@ -441,6 +454,7 @@ public abstract class AbstractFontManager implements FontManager { public class ImageParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"images", "image"}; + private final Map idAllocators = new HashMap<>(); @Override public String[] sectionId() { @@ -452,9 +466,43 @@ public abstract class AbstractFontManager implements FontManager { return LoadingSequence.IMAGE; } + @Override + public void postProcess() { + for (Map.Entry entry : this.idAllocators.entrySet()) { + entry.getValue().processPendingAllocations(); + try { + entry.getValue().saveToCache(); + } catch (IOException e) { + AbstractFontManager.this.plugin.logger().warn("Error while saving codepoint allocation for font " + entry.getKey().asString(), e); + } + } + } + + @Override + public void preProcess() { + this.idAllocators.clear(); + } + + public IdAllocator getOrCreateIdAllocator(Key key) { + return this.idAllocators.computeIfAbsent(key, k -> { + IdAllocator newAllocator = new IdAllocator(plugin.dataFolderPath().resolve("cache").resolve("font").resolve(k.namespace()).resolve(k.value() + ".json")); + newAllocator.reset(Config.codepointStartingValue(k), 1114111); // utf16 + try { + newAllocator.loadFromCache(); + } catch (IOException e) { + AbstractFontManager.this.plugin.logger().warn("Error while loading chars data from cache for font " + k.asString(), e); + } + return newAllocator; + }); + } + + public Map idAllocators() { + return this.idAllocators; + } + @Override public void parseSection(Pack pack, Path path, String node, Key id, Map section) { - if (images.containsKey(id)) { + if (AbstractFontManager.this.images.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.image.duplicate"); } @@ -463,119 +511,165 @@ public abstract class AbstractFontManager implements FontManager { throw new LocalizedResourceConfigException("warning.config.image.missing_file"); } - String resourceLocation = CharacterUtils.replaceBackslashWithSlash(file.toString()); + String resourceLocation = MiscUtils.make(CharacterUtils.replaceBackslashWithSlash(file.toString()), s -> s.endsWith(".png") ? s : s + ".png"); if (!ResourceLocation.isValid(resourceLocation)) { throw new LocalizedResourceConfigException("warning.config.image.invalid_file_chars", resourceLocation); } - - String fontName = section.getOrDefault("font", "minecraft:default").toString(); + String fontName = section.getOrDefault("font", pack.namespace()+ ":default").toString(); if (!ResourceLocation.isValid(fontName)) { throw new LocalizedResourceConfigException("warning.config.image.invalid_font_chars", fontName); } - Key fontKey = Key.withDefaultNamespace(fontName, id.namespace()); - Font font = getOrCreateFont(fontKey); - List chars; + Key fontId = Key.withDefaultNamespace(fontName, id.namespace()); + Font font = getOrCreateFont(fontId); + + IdAllocator allocator = getOrCreateIdAllocator(fontId); + + int rows; + int columns; + List> futureCodepoints = new ArrayList<>(); Object charsObj = ResourceConfigUtils.get(section, "chars", "char"); + // 自动分配 if (charsObj == null) { - throw new LocalizedResourceConfigException("warning.config.image.missing_char"); - } - if (charsObj instanceof List list) { - chars = MiscUtils.getAsStringList(list).stream().map(it -> { - if (it.startsWith("\\u")) { - return CharacterUtils.decodeUnicodeToChars(it); - } else { - return it.toCharArray(); + Object grid = section.get("grid-size"); + if (grid != null) { + String gridString = grid.toString(); + String[] split = gridString.split(","); + if (split.length != 2) { + throw new LocalizedResourceConfigException("warning.config.image.invalid_grid_size", gridString); } - }).toList(); - if (chars.isEmpty()) { + rows = Integer.parseInt(split[0]); + columns = Integer.parseInt(split[1]); + int chars = rows * columns; + if (chars <= 0) { + throw new LocalizedResourceConfigException("warning.config.image.invalid_grid_size", gridString); + } + for (int i = 0; i < rows; i++) { + for (int j = 0; j < columns; j++) { + futureCodepoints.add(allocator.requestAutoId(id.asString() + ":" + i + ":" + j)); + } + } + } else { + rows = 1; + columns = 1; + futureCodepoints.add(allocator.requestAutoId(id.asString())); + } + } + // 使用了list + else if (charsObj instanceof List list) { + List charsList = MiscUtils.getAsStringList(list); + if (charsList.isEmpty() || charsList.getFirst().isEmpty()) { throw new LocalizedResourceConfigException("warning.config.image.missing_char"); } - } else { - if (charsObj instanceof Integer integer) { - chars = List.of(new char[]{(char) integer.intValue()}); + int tempColumns = -1; + rows = charsList.size(); + for (int i = 0; i < charsList.size(); i++) { + String charString = charsList.get(i); + int[] codepoints; + if (charString.startsWith("\\u")) { + codepoints = CharacterUtils.charsToCodePoints(CharacterUtils.decodeUnicodeToChars(charString)); + } else { + codepoints = CharacterUtils.charsToCodePoints(charString.toCharArray()); + } + for (int j = 0; j < codepoints.length; j++) { + futureCodepoints.add(allocator.assignFixedId(id.asString() + ":" + i + ":" + j, codepoints[i])); + } + if (tempColumns == -1) { + tempColumns = codepoints.length; + } else if (tempColumns != codepoints.length) { + throw new LocalizedResourceConfigException("warning.config.image.invalid_codepoint_grid"); + } + } + columns = tempColumns; + } + // 使用了具体的值 + else { + if (charsObj instanceof Integer codepoint) { + futureCodepoints.add(allocator.assignFixedId(id.asString(), codepoint)); + rows = 1; + columns = 1; } else { String character = charsObj.toString(); if (character.isEmpty()) { throw new LocalizedResourceConfigException("warning.config.image.missing_char"); } - if (character.length() == 1) { - chars = List.of(character.toCharArray()); + rows = 1; + int[] codepoints; + if (character.startsWith("\\u")) { + codepoints = CharacterUtils.charsToCodePoints(CharacterUtils.decodeUnicodeToChars(character)); } else { - if (character.startsWith("\\u")) { - chars = List.of(CharacterUtils.decodeUnicodeToChars(character)); - } else { - // ??? TODO 需要测试特殊字符集 -// if (CharacterUtils.containsCombinedCharacter(character)) { -// TranslationManager.instance().log("warning.config.image.invalid_char", path.toString(), id.toString()); -// } - chars = List.of(character.toCharArray()); + codepoints = CharacterUtils.charsToCodePoints(character.toCharArray()); + } + columns = codepoints.length; + for (int i = 0; i < codepoints.length; i++) { + futureCodepoints.add(allocator.assignFixedId(id.asString() + ":0:" + i, codepoints[i])); + } + } + } + + CompletableFutures.allOf(futureCodepoints).thenRun(() -> ResourceConfigUtils.runCatching(path, node, () -> { + int[][] codepointGrid = new int[rows][columns]; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < columns; j++) { + try { + int codepoint = futureCodepoints.get(i * columns + j).get(); + codepointGrid[i][j] = codepoint; + } catch (ExecutionException e) { + Throwable cause = e.getCause(); + if (cause instanceof IdAllocator.IdConflictException conflict) { + throw new LocalizedResourceConfigException("warning.config.image.codepoint.conflict", + fontId.toString(), + CharacterUtils.encodeCharsToUnicode(Character.toChars(conflict.id())), + new String(Character.toChars(conflict.id())), + conflict.previousOwner() + ); + } else if (cause instanceof IdAllocator.IdExhaustedException) { + throw new LocalizedResourceConfigException("warning.config.image.codepoint.exhausted", fontId.asString()); + } + } catch (InterruptedException e) { + AbstractFontManager.this.plugin.logger().warn("Interrupted while allocating codepoint for image " + id.asString(), e); + return; } } } - } - int size = -1; - int[][] codepointGrid = new int[chars.size()][]; - for (int i = 0; i < chars.size(); ++i) { - int[] codepoints = CharacterUtils.charsToCodePoints(chars.get(i)); - for (int codepoint : codepoints) { - if (font.isCodepointInUse(codepoint)) { - BitmapImage image = font.bitmapImageByCodepoint(codepoint); - throw new LocalizedResourceConfigException("warning.config.image.codepoint_conflict", - fontKey.toString(), - CharacterUtils.encodeCharsToUnicode(Character.toChars(codepoint)), - new String(Character.toChars(codepoint)), - image.id().toString()); + Object heightObj = section.get("height"); + if (heightObj == null) { + Key namespacedPath = Key.of(resourceLocation); + Path targetImagePath = pack.resourcePackFolder() + .resolve("assets") + .resolve(namespacedPath.namespace()) + .resolve("textures") + .resolve(namespacedPath.value()); + if (Files.exists(targetImagePath)) { + try (InputStream in = Files.newInputStream(targetImagePath)) { + BufferedImage image = ImageIO.read(in); + heightObj = image.getHeight() / codepointGrid.length; + } catch (IOException e) { + plugin.logger().warn("Failed to load image " + targetImagePath, e); + return; + } + } else { + throw new LocalizedResourceConfigException("warning.config.image.missing_height"); } } - if (codepoints.length == 0) { - throw new LocalizedResourceConfigException("warning.config.image.missing_char"); - } - codepointGrid[i] = codepoints; - if (size == -1) size = codepoints.length; - if (size != codepoints.length) { - throw new LocalizedResourceConfigException("warning.config.image.invalid_codepoint_grid"); - } - } - Object heightObj = section.get("height"); - if (!resourceLocation.endsWith(".png")) resourceLocation += ".png"; + int height = ResourceConfigUtils.getAsInt(heightObj, "height"); + int ascent = ResourceConfigUtils.getAsInt(section.getOrDefault("ascent", height - 1), "ascent"); + if (height < ascent) { + throw new LocalizedResourceConfigException("warning.config.image.height_ascent_conflict", String.valueOf(height), String.valueOf(ascent)); + } - if (heightObj == null) { - Key namespacedPath = Key.of(resourceLocation); - Path targetImagePath = pack.resourcePackFolder() - .resolve("assets") - .resolve(namespacedPath.namespace()) - .resolve("textures") - .resolve(namespacedPath.value()); - if (Files.exists(targetImagePath)) { - try (InputStream in = Files.newInputStream(targetImagePath)) { - BufferedImage image = ImageIO.read(in); - heightObj = image.getHeight() / codepointGrid.length; - } catch (IOException e) { - plugin.logger().warn("Failed to load image " + targetImagePath, e); - return; + BitmapImage bitmapImage = new BitmapImage(id, fontId, height, ascent, resourceLocation, codepointGrid); + for (int[] y : codepointGrid) { + for (int x : y) { + font.addBitmapImage(x, bitmapImage); } - } else { - throw new LocalizedResourceConfigException("warning.config.image.missing_height"); } - } - int height = ResourceConfigUtils.getAsInt(heightObj, "height"); - int ascent = ResourceConfigUtils.getAsInt(section.getOrDefault("ascent", height - 1), "ascent"); - if (height < ascent) { - throw new LocalizedResourceConfigException("warning.config.image.height_ascent_conflict", String.valueOf(height), String.valueOf(ascent)); - } + AbstractFontManager.this.images.put(id, bitmapImage); - BitmapImage bitmapImage = new BitmapImage(id, fontKey, height, ascent, resourceLocation, codepointGrid); - for (int[] y : codepointGrid) { - for (int x : y) { - font.addBitmapImage(x, bitmapImage); - } - } - - images.put(id, bitmapImage); + }, () -> GsonHelper.get().toJson(section))); } } } 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 c887cb246..a4c0164c3 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 @@ -437,7 +437,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } // custom model data 已被用尽,不太可能 else if (throwable instanceof IdAllocator.IdExhaustedException) { - throw new LocalizedResourceConfigException("warning.config.item.custom_model_data.exhausted"); + throw new LocalizedResourceConfigException("warning.config.item.custom_model_data.exhausted", clientBoundMaterial.asString()); } // 未知错误 else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/LootPool.java b/core/src/main/java/net/momirealms/craftengine/core/loot/LootPool.java index 41694006f..f07bd5d3c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/LootPool.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/LootPool.java @@ -8,7 +8,7 @@ import net.momirealms.craftengine.core.loot.function.LootFunction; import net.momirealms.craftengine.core.loot.function.LootFunctions; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.number.NumberProvider; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.MutableInt; import net.momirealms.craftengine.core.util.RandomUtils; @@ -44,7 +44,7 @@ public class LootPool { } if (this.compositeCondition.test(context)) { Consumer> consumer = LootFunction.decorate(this.compositeFunction, lootConsumer, context); - int i = this.rolls.getInt(context) + MCUtils.fastFloor(this.bonusRolls.getFloat(context) * context.luck()); + int i = this.rolls.getInt(context) + MiscUtils.fastFloor(this.bonusRolls.getFloat(context) * context.luck()); for (int j = 0; j < i; ++j) { this.addRandomItem(createFunctionApplier(consumer, context), context); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractLootEntryContainer.java b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractLootEntryContainer.java index 7538d3f7f..0f860d061 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractLootEntryContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/entry/AbstractLootEntryContainer.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.loot.entry; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import java.util.List; import java.util.function.Predicate; @@ -14,7 +14,7 @@ public abstract class AbstractLootEntryContainer implements LootEntryContaine protected AbstractLootEntryContainer(List> conditions) { this.conditions = conditions; - this.compositeCondition = MCUtils.allOf(conditions); + this.compositeCondition = MiscUtils.allOf(conditions); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/loot/function/AbstractLootConditionalFunction.java b/core/src/main/java/net/momirealms/craftengine/core/loot/function/AbstractLootConditionalFunction.java index 89a918222..7169d2cad 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/loot/function/AbstractLootConditionalFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/loot/function/AbstractLootConditionalFunction.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.loot.function; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.loot.LootContext; import net.momirealms.craftengine.core.plugin.context.Condition; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import java.util.List; import java.util.function.Predicate; @@ -14,7 +14,7 @@ public abstract class AbstractLootConditionalFunction implements LootFunction public AbstractLootConditionalFunction(List> predicates) { this.predicates = predicates; - this.compositePredicates = MCUtils.allOf(predicates); + this.compositePredicates = MiscUtils.allOf(predicates); } @Override 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 f74448582..c0b51bace 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 @@ -320,6 +320,9 @@ public abstract class AbstractPackManager implements PackManager { if (namespace.charAt(0) == '.') { continue; } + if (!ResourceLocation.isValidNamespace(namespace)) { + namespace = "minecraft"; + } Path metaFile = path.resolve("pack.yml"); String description = null; String version = null; 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 8f36b8752..357414f9a 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 @@ -137,6 +137,8 @@ public class Config { protected boolean image$illegal_characters_filter$anvil; protected boolean image$illegal_characters_filter$sign; protected boolean image$illegal_characters_filter$book; + protected int image$codepoint_starting_value$default; + protected Map image$codepoint_starting_value$overrides; protected boolean network$intercept_packets$system_chat; protected boolean network$intercept_packets$tab_list; @@ -257,6 +259,7 @@ public class Config { forcedLocale = TranslationManager.parseLocale(config.getString("forced-locale", "")); } + @SuppressWarnings("DuplicatedCode") public void loadFullSettings() { YamlDocument config = settings(); forcedLocale = TranslationManager.parseLocale(config.getString("forced-locale", "")); @@ -429,7 +432,7 @@ public class Config { block$extended_interaction_range = Math.max(config.getDouble("block.predict-breaking.extended-interaction-range", 0.5), 0.0); block$chunk_relighter = config.getBoolean("block.chunk-relighter", true); if (firstTime) { - block$serverside_blocks = config.getInt("block.serverside-blocks", 2000); + block$serverside_blocks = Math.min(config.getInt("block.serverside-blocks", 2000), 10_0000); if (block$serverside_blocks < 0) block$serverside_blocks = 0; } @@ -445,6 +448,22 @@ public class Config { image$illegal_characters_filter$chat = config.getBoolean("image.illegal-characters-filter.chat", true); image$illegal_characters_filter$command = config.getBoolean("image.illegal-characters-filter.command", true); image$illegal_characters_filter$sign = config.getBoolean("image.illegal-characters-filter.sign", true); + + image$codepoint_starting_value$default = config.getInt("image.codepoint-starting-value.default", 0); + Section codepointOverridesSection = config.getSection("image.codepoint-starting-value.overrides"); + if (codepointOverridesSection != null) { + Map codepointOverrides = new HashMap<>(); + for (Map.Entry entry : codepointOverridesSection.getStringRouteMappedValues(false).entrySet()) { + if (entry.getValue() instanceof String s) { + codepointOverrides.put(Key.of(entry.getKey()), Integer.parseInt(s)); + } else if (entry.getValue() instanceof Integer i) { + codepointOverrides.put(Key.of(entry.getKey()), i); + } + } + image$codepoint_starting_value$overrides = codepointOverrides; + } else { + image$codepoint_starting_value$overrides = Map.of(); + } network$intercept_packets$system_chat = config.getBoolean("network.intercept-packets.system-chat", true); network$intercept_packets$tab_list = config.getBoolean("network.intercept-packets.tab-list", true); @@ -780,6 +799,13 @@ public class Config { return instance.item$custom_model_data_starting_value$default; } + public static int codepointStartingValue(Key font) { + if (instance.image$codepoint_starting_value$overrides.containsKey(font)) { + return instance.image$codepoint_starting_value$overrides.get(font); + } + return instance.image$codepoint_starting_value$default; + } + public static int compressionMethod() { int id = instance.chunk_system$compression_method; if (id <= 0 || id > CompressionMethod.METHOD_COUNT) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java index a1776b43d..761f07dc7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AllOfCondition.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.util.Key; -import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -18,7 +17,7 @@ public class AllOfCondition implements Condition { protected final Predicate condition; public AllOfCondition(List> conditions) { - this.condition = MCUtils.allOf(conditions); + this.condition = MiscUtils.allOf(conditions); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java index e01568f5b..278bb9421 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/AnyOfCondition.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.util.Key; -import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; @@ -18,7 +17,7 @@ public class AnyOfCondition implements Condition { protected final Predicate condition; public AnyOfCondition(List> conditions) { - this.condition = MCUtils.anyOf(conditions); + this.condition = MiscUtils.anyOf(conditions); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java index 44d22ba1a..4c20d65a7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/AbstractConditionalFunction.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.plugin.context.function; import net.momirealms.craftengine.core.plugin.context.Condition; import net.momirealms.craftengine.core.plugin.context.Context; -import net.momirealms.craftengine.core.util.MCUtils; import net.momirealms.craftengine.core.util.MiscUtils; import java.util.ArrayList; @@ -16,7 +15,7 @@ public abstract class AbstractConditionalFunction implement public AbstractConditionalFunction(List> predicates) { this.predicates = predicates; - this.compositePredicates = MCUtils.allOf(predicates); + this.compositePredicates = MiscUtils.allOf(predicates); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java index 025cda880..268f23984 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/BreakBlockFunction.java @@ -7,7 +7,7 @@ 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.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import java.util.List; import java.util.Map; @@ -28,7 +28,7 @@ public class BreakBlockFunction extends AbstractConditional @Override public void runInternal(CTX ctx) { Optional optionalPlayer = ctx.getOptionalParameter(DirectContextParameters.PLAYER); - optionalPlayer.ifPresent(player -> player.breakBlock(MCUtils.fastFloor(x.getDouble(ctx)), MCUtils.fastFloor(y.getDouble(ctx)), MCUtils.fastFloor(z.getDouble(ctx)))); + optionalPlayer.ifPresent(player -> player.breakBlock(MiscUtils.fastFloor(x.getDouble(ctx)), MiscUtils.fastFloor(y.getDouble(ctx)), MiscUtils.fastFloor(z.getDouble(ctx)))); } @Override 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 15167ef06..3068766eb 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 @@ -10,7 +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.Key; import net.momirealms.craftengine.core.util.LazyReference; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.world.World; import net.momirealms.craftengine.core.world.WorldPosition; @@ -40,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.get(), this.updateFlags.getInt(ctx)); + world.setBlockAt(MiscUtils.fastFloor(this.x.getDouble(ctx)), MiscUtils.fastFloor(this.y.getDouble(ctx)), MiscUtils.fastFloor(this.z.getDouble(ctx)), this.lazyBlockState.get(), this.updateFlags.getInt(ctx)); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java index 801e13667..020c44fe7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/RunFunction.java @@ -7,7 +7,7 @@ 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.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.WorldPosition; @@ -48,7 +48,7 @@ public class RunFunction extends AbstractConditionalFunctio for (Function function : functions) { function.run(ctx); } - }, delay, pos.world().platformWorld(), MCUtils.fastFloor(pos.x()) >> 4, MCUtils.fastFloor(pos.z()) >> 4); + }, delay, pos.world().platformWorld(), MiscUtils.fastFloor(pos.x()) >> 4, MiscUtils.fastFloor(pos.z()) >> 4); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/GaussianNumberProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/GaussianNumberProvider.java index 77de046d5..4554a46ec 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/GaussianNumberProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/number/GaussianNumberProvider.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.plugin.context.number; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; @@ -54,7 +54,7 @@ public class GaussianNumberProvider implements NumberProvider { } attempts++; } - return MCUtils.clamp(this.mean, this.min, this.max); + return MiscUtils.clamp(this.mean, this.min, this.max); } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java index 465b49809..27529a7e5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/EntityParameterProvider.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.plugin.context.parameter; import net.momirealms.craftengine.core.entity.Entity; import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import java.util.HashMap; import java.util.Map; @@ -19,9 +19,9 @@ public class EntityParameterProvider implements ChainParameterProvider { CONTEXT_FUNCTIONS.put(DirectContextParameters.YAW, Entity::xRot); CONTEXT_FUNCTIONS.put(DirectContextParameters.PITCH, Entity::yRot); CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, Entity::position); - CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); - CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); - CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MiscUtils.fastFloor(p.x())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MiscUtils.fastFloor(p.y())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MiscUtils.fastFloor(p.z())); CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, Entity::name); CONTEXT_FUNCTIONS.put(DirectContextParameters.UUID, Entity::uuid); CONTEXT_FUNCTIONS.put(DirectContextParameters.WORLD, Entity::world); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java index 25c3df127..ee6033ccd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PlayerParameterProvider.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import java.util.HashMap; import java.util.Map; @@ -21,9 +21,9 @@ public class PlayerParameterProvider implements ChainParameterProvider { CONTEXT_FUNCTIONS.put(DirectContextParameters.PITCH, Entity::xRot); CONTEXT_FUNCTIONS.put(DirectContextParameters.YAW, Entity::yRot); CONTEXT_FUNCTIONS.put(DirectContextParameters.POSITION, Entity::position); - CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MCUtils.fastFloor(p.x())); - CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); - CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MiscUtils.fastFloor(p.x())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MiscUtils.fastFloor(p.y())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MiscUtils.fastFloor(p.z())); CONTEXT_FUNCTIONS.put(DirectContextParameters.FOOD, Player::foodLevel); CONTEXT_FUNCTIONS.put(DirectContextParameters.SATURATION, Player::saturation); CONTEXT_FUNCTIONS.put(DirectContextParameters.NAME, Player::name); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java index b7e2b26b6..c646658fb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/parameter/PositionParameterProvider.java @@ -2,7 +2,7 @@ package net.momirealms.craftengine.core.plugin.context.parameter; import net.momirealms.craftengine.core.plugin.context.ChainParameterProvider; import net.momirealms.craftengine.core.plugin.context.ContextKey; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.world.WorldPosition; import java.util.HashMap; @@ -20,9 +20,9 @@ public class PositionParameterProvider implements ChainParameterProvider MCUtils.fastFloor(p.x())); - CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MCUtils.fastFloor(p.y())); - CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MCUtils.fastFloor(p.z())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_X, p -> MiscUtils.fastFloor(p.x())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Y, p -> MiscUtils.fastFloor(p.y())); + CONTEXT_FUNCTIONS.put(DirectContextParameters.BLOCK_Z, p -> MiscUtils.fastFloor(p.z())); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java index edd33b388..b8686e3db 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/selector/AllPlayerSelector.java @@ -8,7 +8,7 @@ import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import java.util.ArrayList; import java.util.Arrays; @@ -21,7 +21,7 @@ public class AllPlayerSelector implements PlayerSelector predicate; public AllPlayerSelector(List> predicates) { - this.predicate = MCUtils.allOf(predicates); + this.predicate = MiscUtils.allOf(predicates); } public AllPlayerSelector() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/codec/NetworkCodecs.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/codec/NetworkCodecs.java index 0589a2df5..a75ebda9d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/codec/NetworkCodecs.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/codec/NetworkCodecs.java @@ -6,7 +6,7 @@ import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.ByteBufUtil; import io.netty.handler.codec.DecoderException; import io.netty.handler.codec.EncoderException; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.NBT; import net.momirealms.sparrow.nbt.Tag; @@ -47,7 +47,7 @@ public interface NetworkCodecs { } }; - NetworkCodec ROTATION_BYTE = BYTE.map(MCUtils::unpackDegrees, MCUtils::packDegrees); + NetworkCodec ROTATION_BYTE = BYTE.map(MiscUtils::unpackDegrees, MiscUtils::packDegrees); NetworkCodec SHORT = new NetworkCodec<>() { @Override 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 index 1c24d56fc..974d1a01d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/registry/ConstantBoundRegistry.java +++ b/core/src/main/java/net/momirealms/craftengine/core/registry/ConstantBoundRegistry.java @@ -3,7 +3,7 @@ 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.MiscUtils; import net.momirealms.craftengine.core.util.ResourceKey; import java.util.IdentityHashMap; @@ -11,7 +11,7 @@ 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 Reference2IntMap toId = MiscUtils.init(new Reference2IntOpenHashMap<>(), map -> map.defaultReturnValue(-1)); protected final Map> byValue; public ConstantBoundRegistry(ResourceKey> key, int expectedSize) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java index 90abef1e1..562e59b81 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java @@ -19,8 +19,7 @@ public class CharacterUtils { for (int i = 0, j = 0; j < count; i += 6, j++) { String hex = unicodeString.substring(i + 2, i + 6); try { - int codePoint = Integer.parseInt(hex, 16); - chars[j] = (char) codePoint; + chars[j] = (char) Integer.parseInt(hex, 16); } catch (NumberFormatException e) { throw new LocalizedResourceConfigException("warning.config.image.invalid_hex_value", e, hex); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Color.java b/core/src/main/java/net/momirealms/craftengine/core/util/Color.java index 6884afedd..5f37d42b0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Color.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Color.java @@ -38,7 +38,7 @@ public class Color { } public static Color fromVector3f(Vector3f vec) { - return new Color(0 << 24 /*不可省略*/ | MCUtils.fastFloor(vec.x) << 16 | MCUtils.fastFloor(vec.y) << 8 | MCUtils.fastFloor(vec.z)); + return new Color(0 << 24 /*不可省略*/ | MiscUtils.fastFloor(vec.x) << 16 | MiscUtils.fastFloor(vec.y) << 8 | MiscUtils.fastFloor(vec.z)); } public static int opaque(int color) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java b/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java index 636d84a0b..8e8e44da1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Direction.java @@ -131,10 +131,10 @@ public enum Direction { public static Direction[] orderedByNearest(AbstractEntity entity) { float f = entity.xRot() * ((float)Math.PI / 180F); float f1 = -entity.yRot() * ((float)Math.PI / 180F); - float sin = MCUtils.sin(f); - float cos = MCUtils.cos(f); - float sin1 = MCUtils.sin(f1); - float cos1 = MCUtils.cos(f1); + float sin = MiscUtils.sin(f); + float cos = MiscUtils.cos(f); + float sin1 = MiscUtils.sin(f1); + float cos1 = MiscUtils.cos(f1); boolean flag = sin1 > 0.0F; boolean flag1 = sin < 0.0F; boolean flag2 = cos1 > 0.0F; 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 62c582ee7..b4b339108 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 @@ -585,7 +585,7 @@ public class FriendlyByteBuf extends ByteBuf { } public BitSet readFixedBitSet(int size) { - byte[] byteArray = new byte[MCUtils.positiveCeilDiv(size, 8)]; + byte[] byteArray = new byte[MiscUtils.positiveCeilDiv(size, 8)]; this.readBytes(byteArray); return BitSet.valueOf(byteArray); } @@ -595,7 +595,7 @@ public class FriendlyByteBuf extends ByteBuf { throw new EncoderException("BitSet length exceeds expected size (" + bitSet.length() + " > " + size + ")"); } byte[] byteArray = bitSet.toByteArray(); - this.writeBytes(Arrays.copyOf(byteArray, MCUtils.positiveCeilDiv(size, 8))); + this.writeBytes(Arrays.copyOf(byteArray, MiscUtils.positiveCeilDiv(size, 8))); } @SuppressWarnings("unchecked") @@ -631,11 +631,11 @@ public class FriendlyByteBuf extends ByteBuf { double d = Double.isNaN(vec3.x) ? (double) 0.0F : Math.clamp(vec3.x, -1.7179869183E10, 1.7179869183E10); double d1 = Double.isNaN(vec3.y) ? (double) 0.0F : Math.clamp(vec3.y, -1.7179869183E10, 1.7179869183E10); double d2 = Double.isNaN(vec3.z) ? (double) 0.0F : Math.clamp(vec3.z, -1.7179869183E10, 1.7179869183E10); - double max = MCUtils.absMax(d, MCUtils.absMax(d1, d2)); + double max = MiscUtils.absMax(d, MiscUtils.absMax(d1, d2)); if (max < 3.051944088384301E-5) { this.writeByte(0); } else { - long l = MCUtils.ceilLong(max); + long l = MiscUtils.ceilLong(max); boolean flag = (l & 3L) != l; long l1 = flag ? l & 3L | 4L : l; long l2 = (Math.round(((d / (double) l) * (double) 0.5F + (double) 0.5F) * (double) 32766.0F)) << 3; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/Int2ObjectBiMap.java b/core/src/main/java/net/momirealms/craftengine/core/util/Int2ObjectBiMap.java index 76cbad82e..5eeb3c669 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/Int2ObjectBiMap.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/Int2ObjectBiMap.java @@ -121,7 +121,7 @@ public class Int2ObjectBiMap implements IndexedIterable { } private int getIdealIndex(@Nullable K value) { - return (MCUtils.idealHash(System.identityHashCode(value)) & Integer.MAX_VALUE) % this.values.length; + return (MiscUtils.idealHash(System.identityHashCode(value)) & Integer.MAX_VALUE) % this.values.length; } private int findIndex(@Nullable K value, int id) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java deleted file mode 100644 index c78fc05d1..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MCUtils.java +++ /dev/null @@ -1,294 +0,0 @@ -package net.momirealms.craftengine.core.util; - -import com.google.common.collect.Iterators; -import org.jetbrains.annotations.Nullable; - -import java.util.Iterator; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Predicate; - -public class MCUtils { - - private MCUtils() {} - - public static final float DEG_TO_RAD = ((float)Math.PI / 180F); - - private static final int[] MULTIPLY_DE_BRUIJN_BIT_POSITION = new int[]{0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; - private static final float[] SIN = make(new float[65536], (sineTable) -> { - for(int i = 0; i < sineTable.length; ++i) { - sineTable[i] = (float) Math.sin((double) i * Math.PI * 2.0 / 65536.0); - } - }); - - public static int fastFloor(double value) { - int truncated = (int) value; - return value < (double) truncated ? truncated - 1 : truncated; - } - - public static int fastFloor(float value) { - int truncated = (int) value; - return value < (double) truncated ? truncated - 1 : truncated; - } - - public static int lerpDiscrete(float delta, int start, int end) { - int i = end - start; - return start + fastFloor(delta * (float) (i - 1)) + (delta > 0.0F ? 1 : 0); - } - - public static int murmurHash3Mixer(int value) { - value ^= value >>> 16; - value *= -2048144789; - value ^= value >>> 13; - value *= -1028477387; - return value ^ value >>> 16; - } - - public static int ceil(double value) { - int i = (int)value; - return value > (double)i ? i + 1 : i; - } - - public static boolean isPowerOfTwo(int value) { - return value != 0 && (value & value - 1) == 0; - } - - public static int smallestEncompassingPowerOfTwo(int value) { - int i = value - 1; - i |= i >> 1; - i |= i >> 2; - i |= i >> 4; - i |= i >> 8; - i |= i >> 16; - return i + 1; - } - - public static int ceilLog2(int value) { - value = isPowerOfTwo(value) ? value : smallestEncompassingPowerOfTwo(value); - return MULTIPLY_DE_BRUIJN_BIT_POSITION[(int)((long)value * 125613361L >> 27) & 31]; - } - - public static int positiveCeilDiv(int a, int b) { - return -Math.floorDiv(-a, b); - } - - public static int idealHash(int value) { - value ^= value >>> 16; - value *= -2048144789; - value ^= value >>> 13; - value *= -1028477387; - value ^= value >>> 16; - return value; - } - - public static long getUnsignedDivisorMagic(final long divisor, final int bits) { - return ((1L << bits) - 1L) / divisor + 1L; - } - - public static T make(T object, Consumer initializer) { - initializer.accept(object); - return object; - } - - public static Predicate allOf() { - return o -> true; - } - - @SuppressWarnings("unchecked") - public static Predicate allOf(Predicate a) { - return (Predicate) a; - } - - public static Predicate allOf(Predicate a, Predicate b) { - return o -> a.test(o) && b.test(o); - } - - public static Predicate allOf(Predicate a, Predicate b, Predicate c) { - return o -> a.test(o) && b.test(o) && c.test(o); - } - - public static Predicate allOf(Predicate a, Predicate b, Predicate c, Predicate d) { - return o -> a.test(o) && b.test(o) && c.test(o) && d.test(o); - } - - public static Predicate allOf(Predicate a, Predicate b, Predicate c, Predicate d, Predicate e) { - return o -> a.test(o) && b.test(o) && c.test(o) && d.test(o) && e.test(o); - } - - @SafeVarargs - public static Predicate allOf(Predicate... predicates) { - return o -> { - for (Predicate predicate : predicates) { - if (!predicate.test(o)) { - return false; - } - } - return true; - }; - } - - public static Predicate allOf(List> predicates) { - return switch (predicates.size()) { - case 0 -> allOf(); - case 1 -> allOf((Predicate) predicates.get(0)); - case 2 -> allOf((Predicate) predicates.get(0), (Predicate) predicates.get(1)); - case 3 -> allOf((Predicate) predicates.get(0), (Predicate) predicates.get(1), (Predicate) predicates.get(2)); - case 4 -> allOf( - (Predicate) predicates.get(0), - (Predicate) predicates.get(1), - (Predicate) predicates.get(2), - (Predicate) predicates.get(3) - ); - case 5 -> allOf( - (Predicate) predicates.get(0), - (Predicate) predicates.get(1), - (Predicate) predicates.get(2), - (Predicate) predicates.get(3), - (Predicate) predicates.get(4) - ); - default -> { - @SuppressWarnings("unchecked") - Predicate[] predicates2 = predicates.toArray(Predicate[]::new); - yield allOf(predicates2); - } - }; - } - - public static Predicate anyOf() { - return o -> false; - } - - @SuppressWarnings("unchecked") - public static Predicate anyOf(Predicate a) { - return (Predicate) a; - } - - public static Predicate anyOf(Predicate a, Predicate b) { - return o -> a.test(o) || b.test(o); - } - - public static Predicate anyOf(Predicate a, Predicate b, Predicate c) { - return o -> a.test(o) || b.test(o) || c.test(o); - } - - public static Predicate anyOf(Predicate a, Predicate b, Predicate c, Predicate d) { - return o -> a.test(o) || b.test(o) || c.test(o) || d.test(o); - } - - public static Predicate anyOf(Predicate a, Predicate b, Predicate c, Predicate d, Predicate e) { - return o -> a.test(o) || b.test(o) || c.test(o) || d.test(o) || e.test(o); - } - - @SafeVarargs - public static Predicate anyOf(Predicate... predicates) { - return o -> { - for (Predicate predicate : predicates) { - if (predicate.test(o)) { - return true; - } - } - return false; - }; - } - - public static Predicate anyOf(List> predicates) { - return switch (predicates.size()) { - case 0 -> anyOf(); - case 1 -> anyOf((Predicate) predicates.get(0)); - case 2 -> anyOf((Predicate) predicates.get(0), (Predicate) predicates.get(1)); - case 3 -> anyOf((Predicate) predicates.get(0), (Predicate) predicates.get(1), (Predicate) predicates.get(2)); - case 4 -> anyOf( - (Predicate) predicates.get(0), - (Predicate) predicates.get(1), - (Predicate) predicates.get(2), - (Predicate) predicates.get(3) - ); - case 5 -> anyOf( - (Predicate) predicates.get(0), - (Predicate) predicates.get(1), - (Predicate) predicates.get(2), - (Predicate) predicates.get(3), - (Predicate) predicates.get(4) - ); - default -> { - @SuppressWarnings("unchecked") - Predicate[] predicates2 = predicates.toArray(Predicate[]::new); - yield anyOf(predicates2); - } - }; - } - - public static T findPreviousInIterable(Iterable iterable, @Nullable T object) { - Iterator iterator = iterable.iterator(); - T previous = null; - while (iterator.hasNext()) { - T current = iterator.next(); - if (current == object) { - if (previous == null) { - previous = iterator.hasNext() ? Iterators.getLast(iterator) : object; - } - break; - } - previous = current; - } - return previous; - } - - public static float sin(float value) { - return SIN[(int) (value * 10430.378F) & '\uffff']; - } - - public static float cos(float value) { - return SIN[(int)(value * 10430.378F + 16384.0F) & '\uffff']; - } - - public static float sqrt(float value) { - return (float)Math.sqrt(value); - } - - public static T findNextInIterable(Iterable iterable, @Nullable T object) { - Iterator iterator = iterable.iterator(); - T next = iterator.next(); - if (object != null) { - T current = next; - while (current != object) { - if (iterator.hasNext()) { - current = iterator.next(); - } - } - if (iterator.hasNext()) { - return iterator.next(); - } - } - return next; - } - - public static byte packDegrees(float degrees) { - return (byte) fastFloor(degrees * 256.0F / 360.0F); - } - - public static float unpackDegrees(byte degrees) { - return (float) (degrees * 360) / 256.0F; - } - - public static int clamp(int value, int min, int max) { - return Math.min(Math.max(value, min), max); - } - - public static float clamp(float value, float min, float max) { - return value < min ? min : Math.min(value, max); - } - - public static double clamp(double value, double min, double max) { - return value < min ? min : Math.min(value, max); - } - - public static double absMax(double x, double y) { - return Math.max(Math.abs(x), Math.abs(y)); - } - - public static long ceilLong(double value) { - long l = (long)value; - return value > (double)l ? l + 1L : l; - } -} 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 8e5a2864a..2e28001c2 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 @@ -1,10 +1,302 @@ package net.momirealms.craftengine.core.util; +import com.google.common.collect.Iterators; +import org.jetbrains.annotations.Nullable; + import java.util.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; public class MiscUtils { + private MiscUtils() { + } - private MiscUtils() {} + public static final float DEG_TO_RAD = ((float) Math.PI / 180F); + + private static final int[] MULTIPLY_DE_BRUIJN_BIT_POSITION = new int[]{0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; + private static final float[] SIN = init(new float[65536], (sineTable) -> { + for (int i = 0; i < sineTable.length; ++i) { + sineTable[i] = (float) Math.sin((double) i * Math.PI * 2.0 / 65536.0); + } + }); + + public static int fastFloor(double value) { + int truncated = (int) value; + return value < (double) truncated ? truncated - 1 : truncated; + } + + public static int fastFloor(float value) { + int truncated = (int) value; + return value < (double) truncated ? truncated - 1 : truncated; + } + + public static int lerpDiscrete(float delta, int start, int end) { + int i = end - start; + return start + fastFloor(delta * (float) (i - 1)) + (delta > 0.0F ? 1 : 0); + } + + public static int murmurHash3Mixer(int value) { + value ^= value >>> 16; + value *= -2048144789; + value ^= value >>> 13; + value *= -1028477387; + return value ^ value >>> 16; + } + + public static int ceil(double value) { + int i = (int) value; + return value > (double) i ? i + 1 : i; + } + + public static boolean isPowerOfTwo(int value) { + return value != 0 && (value & value - 1) == 0; + } + + public static int smallestEncompassingPowerOfTwo(int value) { + int i = value - 1; + i |= i >> 1; + i |= i >> 2; + i |= i >> 4; + i |= i >> 8; + i |= i >> 16; + return i + 1; + } + + public static int ceilLog2(int value) { + value = isPowerOfTwo(value) ? value : smallestEncompassingPowerOfTwo(value); + return MULTIPLY_DE_BRUIJN_BIT_POSITION[(int) ((long) value * 125613361L >> 27) & 31]; + } + + public static int positiveCeilDiv(int a, int b) { + return -Math.floorDiv(-a, b); + } + + public static int idealHash(int value) { + value ^= value >>> 16; + value *= -2048144789; + value ^= value >>> 13; + value *= -1028477387; + value ^= value >>> 16; + return value; + } + + public static long getUnsignedDivisorMagic(final long divisor, final int bits) { + return ((1L << bits) - 1L) / divisor + 1L; + } + + public static T init(T object, Consumer initializer) { + initializer.accept(object); + return object; + } + + public static T make(final T object, Function initializer) { + return initializer.apply(object); + } + + public static Predicate allOf() { + return o -> true; + } + + @SuppressWarnings("unchecked") + public static Predicate allOf(Predicate a) { + return (Predicate) a; + } + + public static Predicate allOf(Predicate a, Predicate b) { + return o -> a.test(o) && b.test(o); + } + + public static Predicate allOf(Predicate a, Predicate b, Predicate c) { + return o -> a.test(o) && b.test(o) && c.test(o); + } + + public static Predicate allOf(Predicate a, Predicate b, Predicate c, Predicate d) { + return o -> a.test(o) && b.test(o) && c.test(o) && d.test(o); + } + + public static Predicate allOf(Predicate a, Predicate b, Predicate c, Predicate d, Predicate e) { + return o -> a.test(o) && b.test(o) && c.test(o) && d.test(o) && e.test(o); + } + + @SafeVarargs + public static Predicate allOf(Predicate... predicates) { + return o -> { + for (Predicate predicate : predicates) { + if (!predicate.test(o)) { + return false; + } + } + return true; + }; + } + + public static Predicate allOf(List> predicates) { + return switch (predicates.size()) { + case 0 -> allOf(); + case 1 -> allOf((Predicate) predicates.get(0)); + case 2 -> allOf((Predicate) predicates.get(0), (Predicate) predicates.get(1)); + case 3 -> + allOf((Predicate) predicates.get(0), (Predicate) predicates.get(1), (Predicate) predicates.get(2)); + case 4 -> allOf( + (Predicate) predicates.get(0), + (Predicate) predicates.get(1), + (Predicate) predicates.get(2), + (Predicate) predicates.get(3) + ); + case 5 -> allOf( + (Predicate) predicates.get(0), + (Predicate) predicates.get(1), + (Predicate) predicates.get(2), + (Predicate) predicates.get(3), + (Predicate) predicates.get(4) + ); + default -> { + @SuppressWarnings("unchecked") + Predicate[] predicates2 = predicates.toArray(Predicate[]::new); + yield allOf(predicates2); + } + }; + } + + public static Predicate anyOf() { + return o -> false; + } + + @SuppressWarnings("unchecked") + public static Predicate anyOf(Predicate a) { + return (Predicate) a; + } + + public static Predicate anyOf(Predicate a, Predicate b) { + return o -> a.test(o) || b.test(o); + } + + public static Predicate anyOf(Predicate a, Predicate b, Predicate c) { + return o -> a.test(o) || b.test(o) || c.test(o); + } + + public static Predicate anyOf(Predicate a, Predicate b, Predicate c, Predicate d) { + return o -> a.test(o) || b.test(o) || c.test(o) || d.test(o); + } + + public static Predicate anyOf(Predicate a, Predicate b, Predicate c, Predicate d, Predicate e) { + return o -> a.test(o) || b.test(o) || c.test(o) || d.test(o) || e.test(o); + } + + @SafeVarargs + public static Predicate anyOf(Predicate... predicates) { + return o -> { + for (Predicate predicate : predicates) { + if (predicate.test(o)) { + return true; + } + } + return false; + }; + } + + public static Predicate anyOf(List> predicates) { + return switch (predicates.size()) { + case 0 -> anyOf(); + case 1 -> anyOf((Predicate) predicates.get(0)); + case 2 -> anyOf((Predicate) predicates.get(0), (Predicate) predicates.get(1)); + case 3 -> + anyOf((Predicate) predicates.get(0), (Predicate) predicates.get(1), (Predicate) predicates.get(2)); + case 4 -> anyOf( + (Predicate) predicates.get(0), + (Predicate) predicates.get(1), + (Predicate) predicates.get(2), + (Predicate) predicates.get(3) + ); + case 5 -> anyOf( + (Predicate) predicates.get(0), + (Predicate) predicates.get(1), + (Predicate) predicates.get(2), + (Predicate) predicates.get(3), + (Predicate) predicates.get(4) + ); + default -> { + @SuppressWarnings("unchecked") + Predicate[] predicates2 = predicates.toArray(Predicate[]::new); + yield anyOf(predicates2); + } + }; + } + + public static T findPreviousInIterable(Iterable iterable, @Nullable T object) { + Iterator iterator = iterable.iterator(); + T previous = null; + while (iterator.hasNext()) { + T current = iterator.next(); + if (current == object) { + if (previous == null) { + previous = iterator.hasNext() ? Iterators.getLast(iterator) : object; + } + break; + } + previous = current; + } + return previous; + } + + public static float sin(float value) { + return SIN[(int) (value * 10430.378F) & '\uffff']; + } + + public static float cos(float value) { + return SIN[(int) (value * 10430.378F + 16384.0F) & '\uffff']; + } + + public static float sqrt(float value) { + return (float) Math.sqrt(value); + } + + public static T findNextInIterable(Iterable iterable, @Nullable T object) { + Iterator iterator = iterable.iterator(); + T next = iterator.next(); + if (object != null) { + T current = next; + while (current != object) { + if (iterator.hasNext()) { + current = iterator.next(); + } + } + if (iterator.hasNext()) { + return iterator.next(); + } + } + return next; + } + + public static byte packDegrees(float degrees) { + return (byte) fastFloor(degrees * 256.0F / 360.0F); + } + + public static float unpackDegrees(byte degrees) { + return (float) (degrees * 360) / 256.0F; + } + + public static int clamp(int value, int min, int max) { + return Math.min(Math.max(value, min), max); + } + + public static float clamp(float value, float min, float max) { + return value < min ? min : Math.min(value, max); + } + + public static double clamp(double value, double min, double max) { + return value < min ? min : Math.min(value, max); + } + + public static double absMax(double x, double y) { + return Math.max(Math.abs(x), Math.abs(y)); + } + + public static long ceilLong(double value) { + long l = (long) value; + return value > (double) l ? l + 1L : l; + } @SuppressWarnings("unchecked") public static Map castToMap(Object obj, boolean allowNull) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/QuaternionUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/QuaternionUtils.java index 96c2081b7..98eaeb41d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/QuaternionUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/QuaternionUtils.java @@ -21,12 +21,12 @@ public class QuaternionUtils { } public static Quaternionf toQuaternionf(float yaw, float pitch, float roll) { - float cy = MCUtils.cos(yaw * 0.5f); - float sy = MCUtils.sin(yaw * 0.5f); - float cp = MCUtils.cos(pitch * 0.5f); - float sp = MCUtils.sin(pitch * 0.5f); - float cr = MCUtils.cos(roll * 0.5f); - float sr = MCUtils.sin(roll * 0.5f); + float cy = MiscUtils.cos(yaw * 0.5f); + float sy = MiscUtils.sin(yaw * 0.5f); + float cp = MiscUtils.cos(pitch * 0.5f); + float sp = MiscUtils.sin(pitch * 0.5f); + float cr = MiscUtils.cos(roll * 0.5f); + float sr = MiscUtils.sin(roll * 0.5f); float w = cr * cp * cy + sr * sp * sy; float x = sr * cp * cy - cr * sp * sy; float y = cr * sp * cy + sr * cp * sy; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java b/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java index 88fe4b680..86905697d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/BlockPos.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.util.Direction; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; public class BlockPos extends Vec3i { public static final BlockPos ZERO = new BlockPos(0, 0, 0); @@ -23,7 +23,7 @@ public class BlockPos extends Vec3i { } public static BlockPos fromVec3d(Vec3d vec) { - return new BlockPos(MCUtils.fastFloor(vec.x), MCUtils.fastFloor(vec.y), MCUtils.fastFloor(vec.z)); + return new BlockPos(MiscUtils.fastFloor(vec.x), MiscUtils.fastFloor(vec.y), MiscUtils.fastFloor(vec.z)); } public static BlockPos of(long packedPos) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/EntityHitResult.java b/core/src/main/java/net/momirealms/craftengine/core/world/EntityHitResult.java index 36c0f2e96..6944337ed 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/EntityHitResult.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/EntityHitResult.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.core.world; import net.momirealms.craftengine.core.util.Direction; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; public class EntityHitResult { private final Direction direction; @@ -23,9 +23,9 @@ public class EntityHitResult { } private BlockPos getBlockPos() { - int x = MCUtils.fastFloor(this.position.x); - int y = MCUtils.fastFloor(this.position.y); - int z = MCUtils.fastFloor(this.position.z); + int x = MiscUtils.fastFloor(this.position.x); + int y = MiscUtils.fastFloor(this.position.y); + int z = MiscUtils.fastFloor(this.position.z); if (this.direction == Direction.UP) { if (this.position.y % 1 == 0) { y--; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java b/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java index 83ac823ba..e24e99037 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/Vec3d.java @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.world; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; public class Vec3d implements Position { public static final Vec3d ZERO = new Vec3d(0, 0, 0); @@ -15,7 +15,7 @@ public class Vec3d implements Position { } public Vec3d toCenter() { - return new Vec3d(MCUtils.fastFloor(x) + 0.5, MCUtils.fastFloor(y) + 0.5, MCUtils.fastFloor(z) + 0.5); + return new Vec3d(MiscUtils.fastFloor(x) + 0.5, MiscUtils.fastFloor(y) + 0.5, MiscUtils.fastFloor(z) + 0.5); } public Vec3d add(Vec3d vec) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java index 211addb11..9ce501846 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/PalettedContainer.java @@ -7,7 +7,7 @@ import net.momirealms.craftengine.core.block.EmptyBlock; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.FriendlyByteBuf; import net.momirealms.craftengine.core.util.IndexedIterable; -import net.momirealms.craftengine.core.util.MCUtils; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.VersionHelper; import org.jetbrains.annotations.Nullable; @@ -269,7 +269,7 @@ public class PalettedContainer implements PaletteResizeListener, ReadableC case 0 -> new DataProvider<>(SINGULAR, bits); case 1, 2, 3, 4 -> new DataProvider<>(ARRAY, 4); case 5, 6, 7, 8 -> new DataProvider<>(BI_MAP, bits); - default -> new DataProvider<>(PaletteProvider.ID_LIST, MCUtils.ceilLog2(idList.size())); + default -> new DataProvider<>(PaletteProvider.ID_LIST, MiscUtils.ceilLog2(idList.size())); }; } }; @@ -278,7 +278,7 @@ public class PalettedContainer implements PaletteResizeListener, ReadableC return switch (bits) { case 0 -> new DataProvider<>(SINGULAR, bits); case 1, 2, 3 -> new DataProvider<>(ARRAY, bits); - default -> new DataProvider<>(PaletteProvider.ID_LIST, MCUtils.ceilLog2(idList.size())); + default -> new DataProvider<>(PaletteProvider.ID_LIST, MiscUtils.ceilLog2(idList.size())); }; } }; @@ -300,7 +300,7 @@ public class PalettedContainer implements PaletteResizeListener, ReadableC public abstract DataProvider createDataProvider(IndexedIterable idList, int bits); int getBits(IndexedIterable idList, int size) { - int i = MCUtils.ceilLog2(size); + int i = MiscUtils.ceilLog2(size); DataProvider dataProvider = this.createDataProvider(idList, i); return dataProvider.factory() == ID_LIST ? i : dataProvider.bits(); } diff --git a/gradle.properties b/gradle.properties index 94725baf0..464ab90be 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,9 +2,9 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.7 +project_version=0.0.63.8 config_version=47 -lang_version=31 +lang_version=32 project_group=net.momirealms latest_supported_version=1.21.8 @@ -15,8 +15,8 @@ supported_languages=en,zh_cn,zh_tw,es,tr,de,ru_ru paper_version=1.21.8 jetbrains_annotations_version=26.0.2 slf4j_version=2.0.17 -log4j_version=2.24.3 -gson_version=2.11.0 +log4j_version=2.25.2 +gson_version=2.13.2 asm_version=9.8 asm_commons_version=9.8 jar_relocator_version=1.7 @@ -29,20 +29,20 @@ 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 +caffeine_version=3.2.2 placeholder_api_version=2.11.6 vault_version=1.7 -guava_version=33.4.6-jre +guava_version=33.5.0-jre lz4_version=1.8.0 geantyref_version=1.3.16 -zstd_version=1.5.7-2 -commons_io_version=2.18.0 +zstd_version=1.5.7-4 +commons_io_version=2.20.0 commons_imaging_version=1.0.0-alpha6 -commons_lang3_version=3.17.0 +commons_lang3_version=3.19.0 sparrow_nbt_version=0.9.4 sparrow_util_version=0.51 -fastutil_version=8.5.15 -netty_version=4.1.124.Final +fastutil_version=8.5.16 +netty_version=4.1.127.Final joml_version=1.10.8 datafixerupper_version=8.0.16 mojang_brigadier_version=1.0.18 @@ -53,9 +53,9 @@ anti_grief_version=0.20 nms_helper_version=1.0.97 evalex_version=3.5.0 reactive_streams_version=1.0.4 -amazon_awssdk_version=2.33.1 +amazon_awssdk_version=2.34.5 amazon_awssdk_eventstream_version=1.0.1 -jimfs_version=1.3.0 +jimfs_version=1.3.1 authlib_version=7.0.60 concurrent_util_version=0.0.3 From c7df9ced635d885c09041f940e9f2af54efe4ef3 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 29 Sep 2025 00:43:59 +0800 Subject: [PATCH 083/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- common-files/src/main/resources/config.yml | 3 ++- common-files/src/main/resources/translations/de.yml | 2 +- common-files/src/main/resources/translations/en.yml | 2 +- .../src/main/resources/translations/ru_ru.yml | 2 +- .../src/main/resources/translations/zh_cn.yml | 2 +- gradle.properties | 12 ++++++------ 7 files changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index daf38199a..26b55747f 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ repositories { ``` ```kotlin dependencies { - compileOnly("net.momirealms:craft-engine-core:0.0.63") - compileOnly("net.momirealms:craft-engine-bukkit:0.0.63") + compileOnly("net.momirealms:craft-engine-core:0.0.64") + compileOnly("net.momirealms:craft-engine-bukkit:0.0.64") } ``` \ No newline at end of file diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index a96c789c1..1ba1c55a3 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -56,7 +56,8 @@ resource-pack: validation: enable: true # [Premium Exclusive] - # Fix images that are not within the texture atlas. + # Fix images that are not within the texture atlas. It is unreasonable to always rely on plugins to fix your mistakes. + # You should strive to make your resource pack more standardized after gaining some experience with resource packs. fix-atlas: true # Define the name of the overlay folders overlay-format: "ce_overlay_{version}" diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 3d10d877e..2b9ac8bc2 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -407,7 +407,7 @@ warning.config.selector.invalid_target: "Problem in Datei gefund warning.config.resource_pack.item_model.already_exist: "Generierung des Item-Models für '' fehlgeschlagen, da die Datei '' bereits existiert." warning.config.resource_pack.model.generation.already_exist: "Generierung des Models fehlgeschlagen, da die Model-Datei '' bereits existiert." warning.config.resource_pack.generation.missing_font_texture: "Beim Font '' fehlt die erforderliche Textur: ''" -warning.config.resource_pack.generation.texture_not_in_atlas: "Textur '' ist nicht im Atlas aufgeführt. Du musst den Texturpfad zum Atlas hinzufügen oder die 'obfuscation'/'fix-atlas'-Option in der config.yml aktivieren." +warning.config.resource_pack.generation.texture_not_in_atlas: "Textur '' ist nicht im Atlas aufgeführt. Du musst den Texturpfad zum Atlas hinzufügen oder die 'fix-atlas'-Option in der config.yml aktivieren." warning.config.resource_pack.generation.missing_model_texture: "Beim Model '' fehlt die Textur ''" warning.config.resource_pack.generation.missing_item_model: "Beim Item '' fehlt die Model-Datei: ''" warning.config.resource_pack.generation.missing_block_model: "Beim Block-State '' fehlt die Model-Datei: ''" diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index a9cf1ec13..655b1c690 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -463,7 +463,7 @@ warning.config.resource_pack.generation.missing_item_model: "Item 'Block state '' is missing model file: ''" warning.config.resource_pack.generation.missing_parent_model: "Model '' cannot find parent model: ''" warning.config.resource_pack.generation.missing_equipment_texture: "Equipment '' is missing 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' or 'fix-atlas' option in config.yml." +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 'fix-atlas' option in config.yml." 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." diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml index baf7bc52c..c3f6229fb 100644 --- a/common-files/src/main/resources/translations/ru_ru.yml +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -376,7 +376,7 @@ 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'/'fix-atlas' опцию в config.yml." +warning.config.resource_pack.generation.texture_not_in_atlas: "Текстура '' не указана в атласе. Вам нужно добавить путь к текстуре в атлас или включить 'fix-atlas' опцию в 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: "В блоке '' отсутствует файл модели: ''" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 21e1bae3b..7c2b3abef 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -444,7 +444,7 @@ warning.config.resource_pack.generation.missing_item_model: "物品'方块状态''缺少模型文件: ''" warning.config.resource_pack.generation.missing_parent_model: "模型''找不到父级模型文件: ''" warning.config.resource_pack.generation.missing_equipment_texture: "装备 '' 缺少纹理 ''" -warning.config.resource_pack.generation.texture_not_in_atlas: "纹理''不在图集内. 你需要将纹理路径或文件夹前缀添加到图集内,或者启用 config.yml 中的 'obfuscation'/'fix-atlas' 或 'fix-atlas' 选项" +warning.config.resource_pack.generation.texture_not_in_atlas: "纹理''不在图集内. 你需要将纹理路径或文件夹前缀添加到图集内,或者启用 config.yml 中的 'fix-atlas' 选项" 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' 参数" diff --git a/gradle.properties b/gradle.properties index 464ab90be..604850d98 100644 --- a/gradle.properties +++ b/gradle.properties @@ -60,9 +60,9 @@ authlib_version=7.0.60 concurrent_util_version=0.0.3 # Proxy settings -systemProp.socks.proxyHost=127.0.0.1 -systemProp.socks.proxyPort=7890 -systemProp.http.proxyHost=127.0.0.1 -systemProp.http.proxyPort=7890 -systemProp.https.proxyHost=127.0.0.1 -systemProp.https.proxyPort=7890 \ No newline at end of file +#systemProp.socks.proxyHost=127.0.0.1 +#systemProp.socks.proxyPort=7890 +#systemProp.http.proxyHost=127.0.0.1 +#systemProp.http.proxyPort=7890 +#systemProp.https.proxyHost=127.0.0.1 +#systemProp.https.proxyPort=7890 \ No newline at end of file From ab68fa13d04995c93f197abfc2b17ddb243db123 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 29 Sep 2025 01:16:44 +0800 Subject: [PATCH 084/125] =?UTF-8?q?=E5=86=8D=E4=BF=AE=E5=A4=8D=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/translations/de.yml | 2 +- .../src/main/resources/translations/en.yml | 3 ++- .../src/main/resources/translations/es.yml | 2 +- .../src/main/resources/translations/ru_ru.yml | 2 +- .../src/main/resources/translations/tr.yml | 2 +- .../src/main/resources/translations/zh_cn.yml | 2 +- .../core/block/AbstractBlockManager.java | 8 ++++-- .../core/block/InactiveCustomBlock.java | 2 ++ .../craftengine/core/util/CharacterUtils.java | 27 +------------------ .../DefaultBlockEntitySerializer.java | 8 +++--- .../DefaultSectionSerializer.java | 3 +-- 11 files changed, 22 insertions(+), 39 deletions(-) diff --git a/common-files/src/main/resources/translations/de.yml b/common-files/src/main/resources/translations/de.yml index 2b9ac8bc2..b3e57e754 100644 --- a/common-files/src/main/resources/translations/de.yml +++ b/common-files/src/main/resources/translations/de.yml @@ -257,7 +257,7 @@ warning.config.block.state.missing_properties: "Problem in Datei warning.config.block.state.missing_appearances: "Problem in Datei gefunden - Beim Block '' fehlt der erforderliche 'appearances'-Abschnitt für 'states'." warning.config.block.state.variant.invalid_appearance: "Problem in Datei gefunden - Der Block '' hat einen Fehler, dass die Variante '' eine nicht existierende Appearance '' verwendet." warning.config.block.state.invalid_vanilla: "Problem in Datei gefunden - Der Block '' verwendet einen ungültigen Vanilla-Block-State ''." -warning.config.block.state.unavailable_vanilla: "Problem in Datei gefunden - Der Block '' verwendet einen nicht verfügbaren Vanilla-Block-State ''. Bitte gib diesen State in der mappings.yml frei." +warning.config.block.state.unavailable_vanilla: "Problem in Datei gefunden - Der Block '' verwendet einen nicht verfügbaren Vanilla-Block-State ''. Bitte gib diesen State in der block-state-mappings frei." warning.config.block.state.invalid_vanilla_id: "Problem in Datei gefunden - Der Block '' verwendet einen Vanilla-Block-State '', der den verfügbaren Slot-Bereich '0~' überschreitet." warning.config.block.state.id.conflict: "Problem in Datei gefunden - Der Block '' konnte den echten Block-State für '' nicht binden, da der State bereits von '' belegt ist." warning.config.block.state.model.missing_path: "Problem in Datei gefunden - Beim Block '' fehlt die erforderliche 'path'-Option für 'model'." diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 655b1c690..5679ea63c 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -129,6 +129,7 @@ warning.config.image.codepoint.exhausted: "Issue found in file - warning.config.image.invalid_codepoint_grid: "Issue found in file - Image '' has an invalid 'chars' codepoint grid." warning.config.image.invalid_char: "Issue found in file - Image '' has a char parameter containing combining characters, which may result in image splitting." warning.config.image.invalid_hex_value: "Issue found in file - The image '' is using a unicode character '' that is not a valid hexadecimal (radix 16) value." +warning.config.image.invalid_unicode_string: "Issue found in file - The image '' is using an incorrect unicode string ''." 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 ''." @@ -276,7 +277,7 @@ warning.config.block.state.entity_renderer.better_model.missing_model: " warning.config.block.state.entity_renderer.model_engine.missing_model: "Issue found in file - The block '' is missing the required 'model' argument for 'model_engine' entity renderer." warning.config.block.state.variant.invalid_appearance: "Issue found in file - The block '' has an error that the variant '' is using a non-existing appearance ''." warning.config.block.state.invalid_vanilla: "Issue found in file - The block '' is using an invalid vanilla block state ''." -warning.config.block.state.unavailable_vanilla: "Issue found in file - The block '' is using an unavailable vanilla block state ''. Please free that state in mappings.yml." +warning.config.block.state.unavailable_vanilla: "Issue found in file - The block '' is using an unavailable vanilla block state ''. Please free that state in block-state-mappings." warning.config.block.state.invalid_vanilla_id: "Issue found in file - The block '' is using a vanilla block state '' that exceeds the available slot range '0~'." warning.config.block.state.invalid_id: "Issue found in file - The block state ID range () used by block '' is outside the valid range of 0 to . Please add more server-side blocks in 'config.yml' if the current slots are exhausted." warning.config.block.state.id.conflict: "Issue found in file - The block '' failed to bind real block state '' for '' as the state has been occupied by ''." diff --git a/common-files/src/main/resources/translations/es.yml b/common-files/src/main/resources/translations/es.yml index 908d1752c..13b0fe348 100644 --- a/common-files/src/main/resources/translations/es.yml +++ b/common-files/src/main/resources/translations/es.yml @@ -180,7 +180,7 @@ warning.config.block.state.missing_properties: "Problema encontrado en e warning.config.block.state.missing_appearances: "Problema encontrado en el archivo - El bloque '' carece de la sección requerida 'appearances' para 'states'." warning.config.block.state.variant.invalid_appearance: "Problema encontrado en el archivo - Hay un error en el bloque '' donde la variante '' está usando una apariencia inexistente ''." warning.config.block.state.invalid_vanilla: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla inválido ''." -warning.config.block.state.unavailable_vanilla: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla no disponible ''. Por favor libera este estado en el archivo mappings.yml." +warning.config.block.state.unavailable_vanilla: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla no disponible ''. Por favor libera este estado en el archivo block-state-mappings." warning.config.block.state.invalid_vanilla_id: "Problema encontrado en el archivo - El bloque '' está usando un estado de bloque vanilla '' que excede el rango de slots disponible '0~'." warning.config.block.state.id.conflict: "Problema encontrado en el archivo - El bloque '' falló al vincular el estado de bloque real para '' porque está ocupado por el estado ''." warning.config.block.state.model.missing_path: "Problema encontrado en el archivo - El bloque '' carece de la opción requerida 'path' para 'model'." diff --git a/common-files/src/main/resources/translations/ru_ru.yml b/common-files/src/main/resources/translations/ru_ru.yml index c3f6229fb..5ae93dfe1 100644 --- a/common-files/src/main/resources/translations/ru_ru.yml +++ b/common-files/src/main/resources/translations/ru_ru.yml @@ -230,7 +230,7 @@ warning.config.block.state.missing_properties: "Проблема най warning.config.block.state.missing_appearances: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'appearances' раздел для 'states'." 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.unavailable_vanilla: "Проблема найдена в файле - Блок '' использует недоступное состояние ванильного блока ''. Пожалуйста, освободите это состояние в block-state-mappings." warning.config.block.state.invalid_vanilla_id: "Проблема найдена в файле - Блок '' использует состояние ванильного блока '', что превышает доступный диапазон слотов '0~'." warning.config.block.state.id.conflict: "Проблема найдена в файле - Блоку '' не удалось привязать реальное состояние блока для '', так как состояние занято ''." warning.config.block.state.model.missing_path: "Проблема найдена в файле - В блоке '' отсутствует необходимый 'path' опция для 'model'." diff --git a/common-files/src/main/resources/translations/tr.yml b/common-files/src/main/resources/translations/tr.yml index 20538d70e..8507154a8 100644 --- a/common-files/src/main/resources/translations/tr.yml +++ b/common-files/src/main/resources/translations/tr.yml @@ -178,7 +178,7 @@ warning.config.block.state.missing_properties: " dosyasında soru warning.config.block.state.missing_appearances: " dosyasında sorun bulundu - '' bloğu, 'states' için gerekli 'appearances' bölümü eksik." warning.config.block.state.variant.invalid_appearance: " dosyasında sorun bulundu - '' bloğunda, '' varyantının var olmayan bir görünüm '' kullandığı bir hata var." warning.config.block.state.invalid_vanilla: " dosyasında sorun bulundu - '' bloğu geçersiz bir vanilya blok durumu '' kullanıyor." -warning.config.block.state.unavailable_vanilla: " dosyasında sorun bulundu - '' bloğu kullanılamayan bir vanilya blok durumu '' kullanıyor. Lütfen bu durumu mappings.yml dosyasında serbest bırakın." +warning.config.block.state.unavailable_vanilla: " dosyasında sorun bulundu - '' bloğu kullanılamayan bir vanilya blok durumu '' kullanıyor. Lütfen bu durumu block-state-mappings dosyasında serbest bırakın." warning.config.block.state.invalid_vanilla_id: " dosyasında sorun bulundu - '' bloğu, mevcut yuva aralığı '0~' aşan bir vanilya blok durumu '' kullanıyor." warning.config.block.state.id.conflict: " dosyasında sorun bulundu - '' bloğu, durum '' tarafından işgal edildiği için '' için gerçek blok durumu bağlamada başarısız oldu." warning.config.block.state.model.missing_path: " dosyasında sorun bulundu - '' bloğu, 'model' için gerekli 'path' seçeneği eksik." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 7c2b3abef..97c6d2d43 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -266,7 +266,7 @@ warning.config.block.state.missing_properties: "在文件 发现 warning.config.block.state.missing_appearances: "在文件 发现问题 - 方块 '' 的 'states' 缺少必需的 'appearances' 段落" warning.config.block.state.variant.invalid_appearance: "在文件 发现问题 - 方块 '' 的变体 '' 使用了不存在的 appearance ''" warning.config.block.state.invalid_vanilla: "在文件 发现问题 - 方块 '' 使用了无效的原版方块状态 ''" -warning.config.block.state.unavailable_vanilla: "在文件 发现问题 - 方块 '' 使用了不可用的原版方块状态 '' 请在 mappings.yml 中释放该状态" +warning.config.block.state.unavailable_vanilla: "在文件 发现问题 - 方块 '' 使用了不可用的原版方块状态 '' 请在 block-state-mappings 中释放该状态" warning.config.block.state.invalid_vanilla_id: "在文件 发现问题 - 方块 '' 使用的原版方块状态 '' 超出可用槽位范围 '0~'" warning.config.block.state.id.conflict: "在文件 发现问题 - 方块 '' 无法为 '' 绑定真实方块状态 '' 因该状态已被 '' 占用" warning.config.block.state.invalid_id: "在文件 发现问题 - 方块 '' 使用的真实方块状态 '' 超出可用槽位范围 '0~' 如果槽位已用尽 请在 config.yml 中添加更多服务端侧方块" diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 13078a68a..898a99a9e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -383,6 +383,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem Map> properties = singleState ? Map.of() : parseBlockProperties(ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("properties"), "warning.config.block.state.missing_properties"), "properties")); // 注册方块容器 Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).getOrRegisterForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), id)); + // 先绑定无效方块 + holder.bindValue(new InactiveCustomBlock(holder)); // 根据properties生成variant provider BlockStateVariantProvider variantProvider = new BlockStateVariantProvider(holder, (owner, propertyMap) -> { @@ -455,8 +457,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem LootTable.fromMap(ResourceConfigUtils.getAsMapOrNull(section.get("loot"), "loot")) ); BlockBehavior blockBehavior = createBlockBehavior(customBlock, MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))); - customBlock.setBehavior(blockBehavior); - holder.bindValue(customBlock); // 单状态 if (singleState) { @@ -555,6 +555,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } + // 一定要到最后再绑定 + customBlock.setBehavior(blockBehavior); + holder.bindValue(customBlock); + // 添加方块 AbstractBlockManager.this.byId.put(customBlock.id(), customBlock); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java index abd181734..524dc7865 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/InactiveCustomBlock.java @@ -1,6 +1,7 @@ package net.momirealms.craftengine.core.block; import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; +import net.momirealms.craftengine.core.block.behavior.EmptyBlockBehavior; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.sparrow.nbt.CompoundTag; @@ -18,6 +19,7 @@ public final class InactiveCustomBlock extends AbstractCustomBlock { public ImmutableBlockState getBlockState(CompoundTag nbt) { return this.cachedData.computeIfAbsent(nbt, k -> { ImmutableBlockState state = new ImmutableBlockState(super.holder, new Reference2ObjectArrayMap<>()); + state.setBehavior(EmptyBlockBehavior.INSTANCE); state.setNbtToSave(state.toNbtToSave(nbt)); return state; }); diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java index 562e59b81..3f069b8ec 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java @@ -6,14 +6,12 @@ import java.util.regex.Pattern; import java.util.stream.IntStream; public class CharacterUtils { - private static final Pattern PATTERN = Pattern.compile("[\\p{Mn}\\p{Me}\\p{Mc}\\p{Cf}]"); - private CharacterUtils() {} public static char[] decodeUnicodeToChars(String unicodeString) { int count = unicodeString.length() / 6; if (unicodeString.length() % 6 != 0) { - throw new LocalizedResourceConfigException("warning.config.image.invalid_unicode_string_length"); + throw new LocalizedResourceConfigException("warning.config.image.invalid_unicode_string", unicodeString); } char[] chars = new char[count]; for (int i = 0, j = 0; j < count; i += 6, j++) { @@ -71,29 +69,6 @@ public class CharacterUtils { return builder.toString(); } - public static boolean containsCombinedCharacter(String input) { - if (input == null || input.isEmpty() || input.length() == 1) return false; - for (int i = 0; i < input.length();) { - int codePoint = input.codePointAt(i); - i += Character.charCount(codePoint); - int type = Character.getType(codePoint); - if (type == Character.NON_SPACING_MARK || - type == Character.ENCLOSING_MARK || - type == Character.COMBINING_SPACING_MARK || - type == Character.FORMAT || - type == Character.CONTROL || - type == Character.SURROGATE || - type == Character.PRIVATE_USE || - PATTERN.matcher(new String(Character.toChars(codePoint))).find() - ) return true; - if (i < input.length()) { - int nextCodePoint = input.codePointAt(i); - if (Character.isSurrogatePair(Character.toChars(codePoint)[0], Character.toChars(nextCodePoint)[0])) return true; - } - } - return false; - } - public static String replaceBackslashWithSlash(String input) { if (input == null || input.isEmpty()) { return input; diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultBlockEntitySerializer.java b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultBlockEntitySerializer.java index 6dfc48961..b72ebf984 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultBlockEntitySerializer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/chunk/serialization/DefaultBlockEntitySerializer.java @@ -38,9 +38,11 @@ public final class DefaultBlockEntitySerializer { } else { BlockPos pos = BlockEntity.readPosAndVerify(data, chunk.chunkPos()); ImmutableBlockState blockState = chunk.getBlockState(pos); - BlockEntity blockEntity = type.factory().create(pos, blockState); - blockEntity.loadCustomData(data); - blockEntities.add(blockEntity); + if (blockState.blockEntityType() == type) { + BlockEntity blockEntity = type.factory().create(pos, blockState); + blockEntity.loadCustomData(data); + blockEntities.add(blockEntity); + } } } return blockEntities; 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 1f0ee3319..991797da3 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 @@ -74,8 +74,7 @@ public final class DefaultSectionSerializer { key = Key.of(id); } Holder owner = BuiltInRegistries.BLOCK.get(key).orElseGet(() -> { - Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder( - ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), key)); + Holder.Reference holder = ((WritableRegistry) BuiltInRegistries.BLOCK).registerForHolder(ResourceKey.create(BuiltInRegistries.BLOCK.key().location(), key)); InactiveCustomBlock inactiveBlock = new InactiveCustomBlock(holder); holder.bindValue(inactiveBlock); return holder; From ef38e23040d03ff2c73a9a68fd3f829876aca26c Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 29 Sep 2025 01:36:35 +0800 Subject: [PATCH 085/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=AD=97=E4=BD=93?= =?UTF-8?q?=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/block/AbstractBlockManager.java | 22 +++++++---- .../core/font/AbstractFontManager.java | 37 +++++++++++-------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 898a99a9e..8f2f9f035 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -46,6 +46,7 @@ import java.io.IOException; import java.nio.file.Path; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; public abstract class AbstractBlockManager extends AbstractModelGenerator implements BlockManager { @@ -428,13 +429,9 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } - CompletableFutures.allOf(internalIdAllocators).thenRun(() -> ResourceConfigUtils.runCatching(path, node, () -> { - for (int i = 0; i < internalIdAllocators.size(); i++) { - CompletableFuture future = internalIdAllocators.get(i); - try { - int internalId = future.get(); - states.get(i).setCustomBlockState(BlockRegistryMirror.byId(internalId + AbstractBlockManager.this.vanillaBlockStateCount)); - } catch (ExecutionException e) { + CompletableFutures.allOf(internalIdAllocators).whenComplete((v, t) -> ResourceConfigUtils.runCatching(path, node, () -> { + if (t != null) { + if (t instanceof CompletionException e) { Throwable cause = e.getCause(); // 这里不会有conflict了,因为之前已经判断过了 if (cause instanceof IdAllocator.IdExhaustedException) { @@ -443,7 +440,16 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem Debugger.BLOCK.warn(() -> "Unknown error while allocating internal block state id.", cause); return; } - } catch (InterruptedException e) { + } + throw new RuntimeException("Unknown error occurred", t); + } + + for (int i = 0; i < internalIdAllocators.size(); i++) { + CompletableFuture future = internalIdAllocators.get(i); + try { + int internalId = future.get(); + states.get(i).setCustomBlockState(BlockRegistryMirror.byId(internalId + AbstractBlockManager.this.vanillaBlockStateCount)); + } catch (InterruptedException | ExecutionException e) { AbstractBlockManager.this.plugin.logger().warn("Interrupted while allocating internal block state for block " + id.asString(), e); return; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 37b33b51b..999dcc6da 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -28,6 +28,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -572,7 +573,7 @@ public abstract class AbstractFontManager implements FontManager { codepoints = CharacterUtils.charsToCodePoints(charString.toCharArray()); } for (int j = 0; j < codepoints.length; j++) { - futureCodepoints.add(allocator.assignFixedId(id.asString() + ":" + i + ":" + j, codepoints[i])); + futureCodepoints.add(allocator.assignFixedId(id.asString() + ":" + i + ":" + j, codepoints[j])); } if (tempColumns == -1) { tempColumns = codepoints.length; @@ -607,26 +608,32 @@ public abstract class AbstractFontManager implements FontManager { } } - CompletableFutures.allOf(futureCodepoints).thenRun(() -> ResourceConfigUtils.runCatching(path, node, () -> { + CompletableFutures.allOf(futureCodepoints).whenComplete((v, t) -> ResourceConfigUtils.runCatching(path, node, () -> { + if (t != null) { + if (t instanceof CompletionException e) { + Throwable cause = e.getCause(); + if (cause instanceof IdAllocator.IdConflictException conflict) { + throw new LocalizedResourceConfigException("warning.config.image.codepoint.conflict", + fontId.toString(), + CharacterUtils.encodeCharsToUnicode(Character.toChars(conflict.id())), + new String(Character.toChars(conflict.id())), + conflict.previousOwner() + ); + } else if (cause instanceof IdAllocator.IdExhaustedException) { + throw new LocalizedResourceConfigException("warning.config.image.codepoint.exhausted", fontId.asString()); + } + } + throw new RuntimeException("Unknown error occurred", t); + } + int[][] codepointGrid = new int[rows][columns]; + for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { try { int codepoint = futureCodepoints.get(i * columns + j).get(); codepointGrid[i][j] = codepoint; - } catch (ExecutionException e) { - Throwable cause = e.getCause(); - if (cause instanceof IdAllocator.IdConflictException conflict) { - throw new LocalizedResourceConfigException("warning.config.image.codepoint.conflict", - fontId.toString(), - CharacterUtils.encodeCharsToUnicode(Character.toChars(conflict.id())), - new String(Character.toChars(conflict.id())), - conflict.previousOwner() - ); - } else if (cause instanceof IdAllocator.IdExhaustedException) { - throw new LocalizedResourceConfigException("warning.config.image.codepoint.exhausted", fontId.asString()); - } - } catch (InterruptedException e) { + } catch (InterruptedException | ExecutionException e) { AbstractFontManager.this.plugin.logger().warn("Interrupted while allocating codepoint for image " + id.asString(), e); return; } From 7d346b97798ee95eace2ab818f01d528f7eef258 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 29 Sep 2025 01:54:45 +0800 Subject: [PATCH 086/125] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/BukkitCraftEngine.java | 14 ++++++++++++++ .../core/block/AbstractBlockManager.java | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) 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 9acb350a2..e5a984612 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 @@ -55,6 +55,7 @@ import org.jspecify.annotations.Nullable; import java.io.*; import java.net.URL; import java.net.URLConnection; +import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.Objects; @@ -210,6 +211,19 @@ public class BukkitCraftEngine extends CraftEngine { super.furnitureManager = new BukkitFurnitureManager(this); super.onPluginEnable(); super.compatibilityManager().onEnable(); + + // todo 未来版本移除 + Path legacyFile1 = this.dataFolderPath().resolve("additional-real-blocks.yml"); + Path legacyFile2 = this.dataFolderPath().resolve("mappings.yml"); + if (Files.exists(legacyFile1)) { + try { + Files.delete(legacyFile1); + Files.deleteIfExists(legacyFile2); + this.saveResource("resources/internal/configuration/mappings.yml"); + } catch (IOException e) { + this.logger.warn("Failed to delete legacy files", e); + } + } } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 8f2f9f035..c9bda8d59 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -674,7 +674,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 获取原版方块的id Key block = split.length == 2 ? Key.of(split[0]) : Key.of(split[0], split[1]); try { - List arranger =blockStateArranger.get(block); + List arranger = AbstractBlockManager.this.blockStateArranger.get(block); if (arranger == null) { throw new LocalizedResourceConfigException("warning.config.block.state.unavailable_vanilla", blockState); } From f08131d771577c3e3eb18e4363e7f692c9d5bd5e Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 29 Sep 2025 02:32:38 +0800 Subject: [PATCH 087/125] =?UTF-8?q?=E5=85=81=E8=AE=B8=E8=AF=AD=E8=A8=80?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=A7=A3=E6=9E=90shift=E5=92=8Cimage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/build.gradle.kts | 2 + .../core/font/AbstractFontManager.java | 6 +- .../craftengine/core/font/FontManager.java | 2 + .../craftengine/core/font/OffsetFont.java | 17 +++-- .../core/pack/LoadingSequence.java | 6 +- .../plugin/locale/TranslationManagerImpl.java | 13 +++- .../core/util/AdventureHelper.java | 70 +++---------------- 7 files changed, 43 insertions(+), 73 deletions(-) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 0694d2128..352ad960b 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -30,6 +30,8 @@ dependencies { compileOnly("net.kyori:adventure-text-serializer-gson:${rootProject.properties["adventure_bundle_version"]}") { exclude("com.google.code.gson", "gson") } + compileOnly("net.kyori:adventure-text-serializer-legacy:${rootProject.properties["adventure_bundle_version"]}") + compileOnly("net.kyori:adventure-text-serializer-json-legacy-impl:${rootProject.properties["adventure_bundle_version"]}") // Command compileOnly("org.incendo:cloud-core:${rootProject.properties["cloud_core_version"]}") diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 999dcc6da..3fbeefb07 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.font; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.core.entity.player.Player; -import net.momirealms.craftengine.core.item.AbstractItemManager; import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.ResourceLocation; @@ -76,6 +75,11 @@ public abstract class AbstractFontManager implements FontManager { this.networkTagMapper = new HashMap<>(1024); } + @Override + public OffsetFont offsetFont() { + return offsetFont; + } + @Override public void unload() { this.fonts.clear(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java index aca5c9dd6..e56e39c3b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java @@ -46,6 +46,8 @@ public interface FontManager extends Manageable { IllegalCharacterProcessResult processIllegalCharacters(String raw, char replacement); + OffsetFont offsetFont(); + ConfigParser[] parsers(); default EmojiTextProcessResult replaceMiniMessageEmoji(@NotNull String miniMessage, @Nullable Player player) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/OffsetFont.java b/core/src/main/java/net/momirealms/craftengine/core/font/OffsetFont.java index c1ae43aa3..26c7cea5a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/OffsetFont.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/OffsetFont.java @@ -12,7 +12,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.BiFunction; public class OffsetFont { - private final String font; + private static OffsetFont instance; + private final net.momirealms.craftengine.core.util.Key font; private final Key fontKey; private final String NEG_16; @@ -39,10 +40,14 @@ public class OffsetFont { .maximumSize(256) .build(); - public OffsetFont(Section section) { - font = section.getString("font", "minecraft:default"); - fontKey = Key.key(font); + public net.momirealms.craftengine.core.util.Key font() { + return font; + } + @SuppressWarnings("all") + public OffsetFont(Section section) { + font = net.momirealms.craftengine.core.util.Key.of(section.getString("font", "minecraft:default")); + fontKey = Key.key(font.namespace(), font.value()); NEG_16 = convertIfUnicode(section.getString("-16", "")); NEG_24 = convertIfUnicode(section.getString("-24", "")); NEG_32 = convertIfUnicode(section.getString("-32", "")); @@ -71,7 +76,7 @@ public class OffsetFont { public String createOffset(int offset, BiFunction tagDecorator) { if (offset == 0) return ""; - return tagDecorator.apply(this.fastLookup.get(offset, k -> k > 0 ? createPos(k) : createNeg(-k)), this.font); + return tagDecorator.apply(this.fastLookup.get(offset, k -> k > 0 ? createPos(k) : createNeg(-k)), this.font.asString()); } @SuppressWarnings("DuplicatedCode") @@ -148,7 +153,7 @@ public class OffsetFont { private String convertIfUnicode(String s) { if (s.startsWith("\\u")) { - return new String(CharacterUtils.decodeUnicodeToChars(font)); + return new String(CharacterUtils.decodeUnicodeToChars(font.asString())); } else { return s; } 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 71368dae1..46e3998aa 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 @@ -4,9 +4,8 @@ public final class LoadingSequence { private LoadingSequence() {} public static final int TEMPLATE = 0; - public static final int BLOCK_STATE_MAPPING = 5; - public static final int GLOBAL_VAR = 10; - public static final int LANG = 20; + public static final int BLOCK_STATE_MAPPING = 10; + public static final int GLOBAL_VAR = 20; public static final int TRANSLATION = 30; public static final int EQUIPMENT = 40; public static final int ITEM = 50; @@ -20,4 +19,5 @@ public final class LoadingSequence { public static final int VANILLA_LOOTS = 130; public static final int EMOJI = 140; public static final int ADVANCEMENT = 150; + public static final int LANG = 160; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index 41b8bb69f..b4e249748 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -2,13 +2,19 @@ package net.momirealms.craftengine.core.plugin.locale; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.core.block.AbstractBlockManager; +import net.momirealms.craftengine.core.font.FontManager; +import net.momirealms.craftengine.core.font.OffsetFont; 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.Plugin; import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.config.*; +import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; +import net.momirealms.craftengine.core.plugin.text.minimessage.ImageTag; import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag; +import net.momirealms.craftengine.core.plugin.text.minimessage.ShiftTag; import net.momirealms.craftengine.core.util.AdventureHelper; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,6 +31,7 @@ import java.nio.file.*; import java.nio.file.attribute.BasicFileAttributes; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; import java.util.stream.Collectors; public class TranslationManagerImpl implements TranslationManager { @@ -276,6 +283,10 @@ public class TranslationManagerImpl implements TranslationManager { public class LangParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"}; + private final Function langProcessor = s -> { + Component deserialize = AdventureHelper.miniMessage().deserialize(AdventureHelper.legacyToMiniMessage(s), ShiftTag.INSTANCE, ImageTag.INSTANCE); + return AdventureHelper.getLegacy().serialize(deserialize); + }; @Override public int loadingSequence() { @@ -293,7 +304,7 @@ public class TranslationManagerImpl implements TranslationManager { Map sectionData = section.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, - entry -> String.valueOf(entry.getValue()) + entry -> this.langProcessor.apply(String.valueOf(entry.getValue())) )); TranslationManagerImpl.this.addClientTranslation(langId, sectionData); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index a8ad7ed18..bc134b433 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -9,10 +9,12 @@ import net.kyori.adventure.text.ComponentIteratorType; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.internal.parser.TokenParser; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.json.JSONOptions; import net.kyori.adventure.text.serializer.json.legacyimpl.NBTLegacyHoverEventSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.momirealms.craftengine.core.plugin.context.Context; import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; import net.momirealms.sparrow.nbt.Tag; @@ -33,6 +35,7 @@ public class AdventureHelper { private final MiniMessage miniMessageCustom; private final GsonComponentSerializer gsonComponentSerializer; private final NBTComponentSerializer nbtComponentSerializer; + private final LegacyComponentSerializer legacyComponentSerializer; private static final TextReplacementConfig REPLACE_LF = TextReplacementConfig.builder().matchLiteral("\n").replacement(Component.newline()).build(); /** * This iterator slices a component into individual parts that @@ -65,6 +68,7 @@ public class AdventureHelper { b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, true); }); } + this.legacyComponentSerializer = LegacyComponentSerializer.builder().build(); this.gsonComponentSerializer = builder.build(); this.nbtComponentSerializer = NBTComponentSerializer.builder() .editItem(item -> { @@ -84,20 +88,10 @@ public class AdventureHelper { private static final AdventureHelper INSTANCE = new AdventureHelper(); } - /** - * Retrieves the singleton instance of AdventureHelper. - * - * @return the singleton instance - */ public static AdventureHelper getInstance() { return SingletonHolder.INSTANCE; } - /** - * Retrieves the MiniMessage instance. - * - * @return the MiniMessage instance - */ public static MiniMessage miniMessage() { return getInstance().miniMessage; } @@ -106,70 +100,22 @@ public class AdventureHelper { return getInstance().miniMessageCustom; } + public static LegacyComponentSerializer getLegacy() { + return getInstance().legacyComponentSerializer; + } + public static MiniMessage strictMiniMessage() { return getInstance().miniMessageStrict; } - /** - * Retrieves the GsonComponentSerializer instance. - * - * @return the GsonComponentSerializer instance - */ public static GsonComponentSerializer getGson() { return getInstance().gsonComponentSerializer; } - /** - * Retrieves the NBTComponentSerializer instance. - * - * @return the NBTComponentSerializer instance - */ public static NBTComponentSerializer getNBT() { return getInstance().nbtComponentSerializer; } - /** - * Sends a message to an audience. - * - * @param audience the audience to send the message to - * @param message the message component - */ - public static void sendMessage(Audience audience, Component message) { - audience.sendMessage(message); - } - - /** - * Plays a sound for an audience. - * - * @param audience the audience to play the sound for - * @param sound the sound to play - */ - public static void playSound(Audience audience, Sound sound) { - audience.playSound(sound); - } - - /** - * Surrounds text with a MiniMessage font tag. - * - * @param text the text to surround - * @param font the font as a {@link Key} - * @return the text surrounded by the MiniMessage font tag - */ - public static String surroundWithMiniMessageFont(String text, Key font) { - return "" + text + ""; - } - - /** - * Surrounds text with a MiniMessage font tag. - * - * @param text the text to surround - * @param font the font as a {@link String} - * @return the text surrounded by the MiniMessage font tag - */ - public static String surroundWithMiniMessageFont(String text, String font) { - return "" + text + ""; - } - /** * Converts a JSON string to a MiniMessage string. * From 66cd1c0962690b3ee71fb27b993a99bf3c1eb7fd Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 29 Sep 2025 05:16:20 +0800 Subject: [PATCH 088/125] =?UTF-8?q?=E5=A4=96=E8=A7=82=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=88=86=E9=85=8Dpart=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/block/BukkitBlockManager.java | 9 +- .../bukkit/block/BukkitBlockStateWrapper.java | 34 -------- .../block/BukkitCustomBlockStateWrapper.java | 46 ++++++++++ .../block/BukkitVanillaBlockStateWrapper.java | 36 ++++++++ .../block/behavior/DoorBlockBehavior.java | 4 +- .../behavior/DoubleHighBlockBehavior.java | 2 +- ...hedHorizontalDirectionalBlockBehavior.java | 2 +- .../block/behavior/SlabBlockBehavior.java | 2 +- .../block/behavior/SofaBlockBehavior.java | 2 +- .../block/behavior/StairsBlockBehavior.java | 4 +- .../block/behavior/TrapDoorBlockBehavior.java | 2 +- .../bukkit/util/StairsShapeUtils.java | 2 +- .../bukkit/world/BukkitExistingBlock.java | 6 +- .../core/block/AbstractBlockManager.java | 59 +++++++------ .../core/block/AbstractBlockStateWrapper.java | 21 +++++ .../core/block/AutoStateGroup.java | 84 +++++++++++++++++++ .../craftengine/core/block/BlockKeys.java | 16 ++++ .../core/block/BlockStateHolder.java | 2 +- .../core/block/BlockStateWrapper.java | 6 ++ .../{state => }/StatePropertyAccessor.java | 2 +- .../core/block/properties/Properties.java | 3 +- .../block/properties/type/AnchorType.java | 7 ++ .../core/block/properties/type/DoorHinge.java | 5 ++ .../properties/type/DoubleBlockHalf.java | 5 ++ .../properties/type/SingleBlockHalf.java | 5 ++ .../core/block/properties/type/SlabType.java | 7 ++ .../type}/SofaShape.java | 2 +- .../type}/StairsShape.java | 2 +- .../block/state/properties/AnchorType.java | 7 -- .../block/state/properties/DoorHinge.java | 5 -- .../state/properties/DoubleBlockHalf.java | 5 -- .../state/properties/SingleBlockHalf.java | 5 -- .../core/block/state/properties/SlabType.java | 7 -- .../core/font/AbstractFontManager.java | 2 +- .../core/item/AbstractItemManager.java | 2 +- .../pack/allocator/BlockStateAllocator.java | 33 ++++++++ .../pack/allocator/BlockStateCandidate.java | 24 ++++++ .../{cache => allocator}/IdAllocator.java | 2 +- .../MatchBlockPropertyCondition.java | 2 +- .../core/plugin/locale/I18NData.java | 2 +- .../plugin/locale/TranslationManagerImpl.java | 4 - .../core/util/AdventureHelper.java | 4 - .../craftengine/core/util/CharacterUtils.java | 1 - .../craftengine/core/world/ExistingBlock.java | 2 +- gradle.properties | 2 +- 45 files changed, 359 insertions(+), 127 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockStateWrapper.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java rename core/src/main/java/net/momirealms/craftengine/core/block/{state => }/StatePropertyAccessor.java (83%) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/properties/type/AnchorType.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoorHinge.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoubleBlockHalf.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SingleBlockHalf.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SlabType.java rename core/src/main/java/net/momirealms/craftengine/core/block/{state/properties => properties/type}/SofaShape.java (53%) rename core/src/main/java/net/momirealms/craftengine/core/block/{state/properties => properties/type}/StairsShape.java (62%) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AnchorType.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/state/properties/DoorHinge.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/state/properties/DoubleBlockHalf.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SingleBlockHalf.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SlabType.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateAllocator.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateCandidate.java rename core/src/main/java/net/momirealms/craftengine/core/pack/{cache => allocator}/IdAllocator.java (99%) 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 705ef4dd4..304156691 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 @@ -353,10 +353,13 @@ public final class BukkitBlockManager extends AbstractBlockManager { private void initMirrorRegistry() { int size = RegistryUtils.currentBlockRegistrySize(); BlockStateWrapper[] states = new BlockStateWrapper[size]; - for (int i = 0; i < size; i++) { - states[i] = new BukkitBlockStateWrapper(BlockStateUtils.idToBlockState(i), i); + for (int i = 0; i < this.vanillaBlockStateCount; i++) { + states[i] = new BukkitVanillaBlockStateWrapper(BlockStateUtils.idToBlockState(i), i); } - BlockRegistryMirror.init(states, new BukkitBlockStateWrapper(MBlocks.STONE$defaultState, BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState))); + for (int i = this.vanillaBlockStateCount; i < size; i++) { + states[i] = new BukkitCustomBlockStateWrapper(BlockStateUtils.idToBlockState(i), i); + } + BlockRegistryMirror.init(states, states[BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState)]); } // 注册服务端侧的真实方块 diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockStateWrapper.java deleted file mode 100644 index 8d0190d76..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockStateWrapper.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.momirealms.craftengine.bukkit.block; - -import net.momirealms.craftengine.core.block.BlockStateWrapper; -import net.momirealms.craftengine.core.util.Key; - -public class BukkitBlockStateWrapper implements BlockStateWrapper { - private final Object blockState; - private final int registryId; - - public BukkitBlockStateWrapper(Object blockState, int registryId) { - this.blockState = blockState; - this.registryId = registryId; - } - - @Override - public Object literalObject() { - return this.blockState; - } - - @Override - public int registryId() { - return this.registryId; - } - - @Override - public String toString() { - return this.blockState.toString(); - } - - @Override - public Key ownerId() { - return null; - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java new file mode 100644 index 000000000..f67d21749 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java @@ -0,0 +1,46 @@ +package net.momirealms.craftengine.bukkit.block; + +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.core.block.AbstractBlockStateWrapper; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.properties.Property; +import net.momirealms.craftengine.core.util.Key; + +import java.util.Optional; + +public class BukkitCustomBlockStateWrapper extends AbstractBlockStateWrapper { + + public BukkitCustomBlockStateWrapper(Object blockState, int registryId) { + super(blockState, registryId); + } + + @Override + public Key ownerId() { + return getImmutableBlockState().map(state -> state.owner().key().location()).orElseGet(() -> BlockStateUtils.getBlockOwnerIdFromState(super.blockState)); + } + + @SuppressWarnings("unchecked") + @Override + public T getProperty(String propertyName) { + return (T) getImmutableBlockState().map(state -> { + Property property = state.owner().value().getProperty(propertyName); + if (property == null) + return null; + return state.getNullable(property); + }).orElse(null); + } + + @Override + public boolean hasProperty(String propertyName) { + return getImmutableBlockState().map(state -> state.owner().value().getProperty(propertyName) != null).orElse(false); + } + + @Override + public String getAsString() { + return getImmutableBlockState().map(ImmutableBlockState::toString).orElseGet(() -> BlockStateUtils.fromBlockData(super.blockState).getAsString()); + } + + public Optional getImmutableBlockState() { + return BlockStateUtils.getOptionalCustomBlockState(super.blockState); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java new file mode 100644 index 000000000..9a13a5d13 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java @@ -0,0 +1,36 @@ +package net.momirealms.craftengine.bukkit.block; + +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; +import net.momirealms.craftengine.core.block.AbstractBlockStateWrapper; +import net.momirealms.craftengine.core.block.StatePropertyAccessor; +import net.momirealms.craftengine.core.util.Key; + +public class BukkitVanillaBlockStateWrapper extends AbstractBlockStateWrapper { + private final StatePropertyAccessor accessor; + + public BukkitVanillaBlockStateWrapper(Object blockState, int registryId) { + super(blockState, registryId); + this.accessor = FastNMS.INSTANCE.createStatePropertyAccessor(blockState); + } + + @Override + public Key ownerId() { + return BlockStateUtils.getBlockOwnerIdFromState(super.blockState); + } + + @Override + public T getProperty(String propertyName) { + return this.accessor.getPropertyValue(propertyName); + } + + @Override + public boolean hasProperty(String propertyName) { + return this.accessor.hasProperty(propertyName); + } + + @Override + public String getAsString() { + return BlockStateUtils.fromBlockData(super.blockState).getAsString(); + } +} 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 864563451..677e9dd1c 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 @@ -16,8 +16,8 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; 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.block.properties.type.DoorHinge; +import net.momirealms.craftengine.core.block.properties.type.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; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java index 723af40e4..a60b2597f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/DoubleHighBlockBehavior.java @@ -9,7 +9,7 @@ import net.momirealms.craftengine.bukkit.util.LocationUtils; 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.block.properties.type.DoubleBlockHalf; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.ResourceConfigUtils; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java index 597470895..dae5a50b3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FaceAttachedHorizontalDirectionalBlockBehavior.java @@ -11,7 +11,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.block.state.properties.AnchorType; +import net.momirealms.craftengine.core.block.properties.type.AnchorType; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.HorizontalDirection; 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 3eaf4efcd..f44f55c3a 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 @@ -10,7 +10,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.block.state.properties.SlabType; +import net.momirealms.craftengine.core.block.properties.type.SlabType; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.behavior.BlockBoundItemBehavior; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SofaBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SofaBlockBehavior.java index 7d7498c36..4259fd8e4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SofaBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/SofaBlockBehavior.java @@ -10,7 +10,7 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.block.state.properties.SofaShape; +import net.momirealms.craftengine.core.block.properties.type.SofaShape; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.HorizontalDirection; 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 2ad532eed..1fa475582 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 @@ -10,8 +10,8 @@ import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.block.state.properties.SingleBlockHalf; -import net.momirealms.craftengine.core.block.state.properties.StairsShape; +import net.momirealms.craftengine.core.block.properties.type.SingleBlockHalf; +import net.momirealms.craftengine.core.block.properties.type.StairsShape; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.HorizontalDirection; 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 71db218b5..e945d546c 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 @@ -15,7 +15,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.block.state.properties.SingleBlockHalf; +import net.momirealms.craftengine.core.block.properties.type.SingleBlockHalf; import net.momirealms.craftengine.core.entity.player.InteractionResult; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/StairsShapeUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/StairsShapeUtils.java index dde8b33f7..bd6175bcd 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/StairsShapeUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/StairsShapeUtils.java @@ -1,7 +1,7 @@ package net.momirealms.craftengine.bukkit.util; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.core.block.state.properties.StairsShape; +import net.momirealms.craftengine.core.block.properties.type.StairsShape; public final class StairsShapeUtils { private StairsShapeUtils() {} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitExistingBlock.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitExistingBlock.java index 0c8d61650..22402fadc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitExistingBlock.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitExistingBlock.java @@ -7,11 +7,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.LocationUtils; -import net.momirealms.craftengine.core.block.BlockRegistryMirror; -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.state.StatePropertyAccessor; +import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.ExistingBlock; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index c9bda8d59..ef7d9d282 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -18,7 +18,9 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.pack.ResourceLocation; -import net.momirealms.craftengine.core.pack.cache.IdAllocator; +import net.momirealms.craftengine.core.pack.allocator.BlockStateAllocator; +import net.momirealms.craftengine.core.pack.allocator.IdAllocator; +import net.momirealms.craftengine.core.pack.allocator.BlockStateCandidate; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -68,8 +70,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final Map> appearanceToRealState = new Int2ObjectOpenHashMap<>(); // 用于note_block:0这样格式的自动分配 protected final Map> blockStateArranger = new HashMap<>(); - // 根据registry id找note_block:x中的x值 - protected final Map reversedBlockStateArranger = new HashMap<>(); // 全方块状态映射文件,用于网络包映射 protected final int[] blockStateMappings; // 原版方块状态数量 @@ -82,6 +82,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final ImmutableBlockState[] immutableBlockStates; // 原版方块的属性缓存 protected final BlockSettings[] vanillaBlockSettings; + // 倒推缓存 + protected final BlockStateCandidate[] reversedBlockStateArranger; // 临时存储哪些视觉方块被使用了 protected final Set tempVisualBlockStatesInUse = new HashSet<>(); protected final Set tempVisualBlocksInUse = new HashSet<>(); @@ -99,6 +101,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.vanillaBlockSettings = new BlockSettings[vanillaBlockStateCount]; this.immutableBlockStates = new ImmutableBlockState[customBlockCount]; this.blockStateMappings = new int[customBlockCount + vanillaBlockStateCount]; + this.reversedBlockStateArranger = new BlockStateCandidate[vanillaBlockStateCount]; Arrays.fill(this.blockStateMappings, -1); } @@ -127,10 +130,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.modBlockStateOverrides.clear(); this.byId.clear(); this.blockStateArranger.clear(); - this.reversedBlockStateArranger.clear(); this.appearanceToRealState.clear(); Arrays.fill(this.blockStateMappings, -1); Arrays.fill(this.immutableBlockStates, EmptyBlock.STATE); + Arrays.fill(this.reversedBlockStateArranger, null); } @Override @@ -272,9 +275,11 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem continue; } AbstractBlockManager.this.blockStateMappings[beforeState.registryId()] = afterState.registryId(); - List blockStateWrappers = AbstractBlockManager.this.blockStateArranger.computeIfAbsent(getBlockOwnerId(beforeState), k -> new ArrayList<>()); + Key blockOwnerId = getBlockOwnerId(beforeState); + List blockStateWrappers = AbstractBlockManager.this.blockStateArranger.computeIfAbsent(blockOwnerId, k -> new ArrayList<>()); blockStateWrappers.add(beforeState); - AbstractBlockManager.this.reversedBlockStateArranger.put(beforeState.registryId(), blockStateWrappers.size() - 1); + AbstractBlockManager.this.reversedBlockStateArranger[beforeState.registryId()] = blockParser.createVisualBlockCandidate(beforeState); + } exceptionCollector.throwIfPresent(); } @@ -283,8 +288,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem public class BlockParser implements IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; private final IdAllocator internalIdAllocator; - private final Map appearanceIdAllocators = new HashMap<>(); private final List pendingConfigSections = new ArrayList<>(); + private final BlockStateAllocator[] visualBlockStateAllocators = new BlockStateAllocator[AutoStateGroup.values().length]; public BlockParser() { this.internalIdAllocator = new IdAllocator(AbstractBlockManager.this.plugin.dataFolderPath().resolve("cache").resolve("custom-block-states.json")); @@ -294,6 +299,29 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.pendingConfigSections.add(section); } + @Nullable + public BlockStateCandidate createVisualBlockCandidate(BlockStateWrapper blockState) { + List groups = AutoStateGroup.findGroups(blockState); + if (!groups.isEmpty()) { + BlockStateCandidate candidate = new BlockStateCandidate(blockState); + for (AutoStateGroup group : groups) { + getOrCreateBlockStateAllocator(group).addCandidate(candidate); + } + return candidate; + } + return null; + } + + private BlockStateAllocator getOrCreateBlockStateAllocator(AutoStateGroup group) { + int index = group.ordinal(); + BlockStateAllocator visualBlockStateAllocator = this.visualBlockStateAllocators[index]; + if (visualBlockStateAllocator == null) { + visualBlockStateAllocator = new BlockStateAllocator(); + this.visualBlockStateAllocators[index] = visualBlockStateAllocator; + } + return visualBlockStateAllocator; + } + @Override public void postProcess() { this.internalIdAllocator.processPendingAllocations(); @@ -323,23 +351,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.pendingConfigSections.clear(); } - @Nullable - public IdAllocator getOrCreateAppearanceIdAllocator(Key type) { - if (!AbstractBlockManager.this.blockStateArranger.containsKey(type)) { - return null; - } - return this.appearanceIdAllocators.computeIfAbsent(type, k -> { - IdAllocator newAllocator = new IdAllocator(plugin.dataFolderPath().resolve("cache").resolve("visual-block-states").resolve(k.value() + ".json")); - newAllocator.reset(0, AbstractBlockManager.this.blockStateArranger.get(type).size()); - try { - newAllocator.loadFromCache(); - } catch (IOException e) { - AbstractBlockManager.this.plugin.logger().warn("Error while loading visual block states cache for block " + k.asString(), e); - } - return newAllocator; - }); - } - @Override public String[] sectionId() { return CONFIG_SECTION_NAME; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java new file mode 100644 index 000000000..fd3f67fbe --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java @@ -0,0 +1,21 @@ +package net.momirealms.craftengine.core.block; + +public abstract class AbstractBlockStateWrapper implements BlockStateWrapper { + protected final Object blockState; + protected final int registryId; + + protected AbstractBlockStateWrapper(Object blockState, int registryId) { + this.blockState = blockState; + this.registryId = registryId; + } + + @Override + public Object literalObject() { + return this.blockState; + } + + @Override + public int registryId() { + return this.registryId; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java b/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java new file mode 100644 index 000000000..b79a46f55 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java @@ -0,0 +1,84 @@ +package net.momirealms.craftengine.core.block; + +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.Predicate; + +public enum AutoStateGroup { + LEAVES("leaves", + Set.of(BlockKeys.OAK_LEAVES, BlockKeys.SPRUCE_LEAVES, BlockKeys.BIRCH_LEAVES, BlockKeys.JUNGLE_LEAVES, BlockKeys.ACACIA_LEAVES, BlockKeys.DARK_OAK_LEAVES, BlockKeys.MANGROVE_LEAVES, BlockKeys.CHERRY_LEAVES, BlockKeys.PALE_OAK_LEAVES, BlockKeys.AZALEA_LEAVES, BlockKeys.FLOWERING_AZALEA_LEAVES), + (w) -> !(boolean) w.getProperty("waterlogged"), 0 + ), + WATERLOGGED_LEAVES( + "waterlogged_leaves", + Set.of(BlockKeys.OAK_LEAVES, BlockKeys.SPRUCE_LEAVES, BlockKeys.BIRCH_LEAVES, BlockKeys.JUNGLE_LEAVES, BlockKeys.ACACIA_LEAVES, BlockKeys.DARK_OAK_LEAVES, BlockKeys.MANGROVE_LEAVES, BlockKeys.CHERRY_LEAVES, BlockKeys.PALE_OAK_LEAVES, BlockKeys.AZALEA_LEAVES, BlockKeys.FLOWERING_AZALEA_LEAVES), + (w) -> w.getProperty("waterlogged"), 0 + ), + TRIPWIRE("tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> true, 1), + LOWER_TRIPWIRE("lower_tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> w.getProperty("attached"), 0), + HIGHER_TRIPWIRE("higher_tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> !(boolean) w.getProperty("attached"), 0), + NOTE_BLOCK("note_block", Set.of(BlockKeys.NOTE_BLOCK), (w) -> true, 0), + BROWN_MUSHROOM("brown_mushroom", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK), (w) -> true, 0), + RED_MUSHROOM("red_mushroom", Set.of(BlockKeys.RED_MUSHROOM_BLOCK), (w) -> true, 0), + MUSHROOM_STEM("mushroom_stem", Set.of(BlockKeys.MUSHROOM_STEM), (w) -> true, 0), + MUSHROOM("mushroom", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK, BlockKeys.RED_MUSHROOM_BLOCK, BlockKeys.MUSHROOM_STEM), (w) -> true, 1), + SOLID("solid", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK, BlockKeys.RED_MUSHROOM_BLOCK, BlockKeys.MUSHROOM_STEM, BlockKeys.NOTE_BLOCK), (w) -> true, 2); + + private final Set blocks; + private final String id; + private final Predicate predicate; + private final int priority; + + AutoStateGroup(String id, Set blocks, Predicate predicate, int priority) { + this.id = id; + this.blocks = blocks; + this.predicate = predicate; + this.priority = priority; + } + + public int priority() { + return priority; + } + + public Set blocks() { + return blocks; + } + + public String id() { + return id; + } + + private static final Map BY_ID = new HashMap<>(); + private static final Map> BY_BLOCKS = new HashMap<>(); + + static { + for (AutoStateGroup group : AutoStateGroup.values()) { + BY_ID.put(group.id(), group); + BY_ID.put(group.id().toUpperCase(Locale.ROOT), group); + for (Key key : group.blocks) { + BY_BLOCKS.computeIfAbsent(key, k -> new ArrayList<>(4)).add(group); + } + } + } + + @Nullable + public static AutoStateGroup byId(String id) { + return BY_ID.get(id); + } + + public static List findGroups(BlockStateWrapper wrapper) { + return findGroups(wrapper.ownerId(), wrapper); + } + + public static List findGroups(Key id, BlockStateWrapper wrapper) { + List groups = BY_BLOCKS.get(id); + if (groups == null) return Collections.emptyList(); + List result = new ArrayList<>(groups.size()); + for (AutoStateGroup group : groups) { + if (group.predicate.test(wrapper)) result.add(group); + } + return result; + } +} 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 ce9cf8079..30490bbad 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 @@ -246,6 +246,22 @@ public final class BlockKeys { public static final Key CACTUS = Key.of("minecraft:cactus"); + public static final Key BROWN_MUSHROOM_BLOCK = Key.of("minecraft:brown_mushroom_block"); + public static final Key RED_MUSHROOM_BLOCK = Key.of("minecraft:red_mushroom_block"); + public static final Key MUSHROOM_STEM = Key.of("minecraft:mushroom_stem"); + + public static final Key OAK_LEAVES = Key.of("minecraft:oak_leaves"); + public static final Key SPRUCE_LEAVES = Key.of("minecraft:spruce_leaves"); + public static final Key BIRCH_LEAVES = Key.of("minecraft:birch_leaves"); + public static final Key JUNGLE_LEAVES = Key.of("minecraft:jungle_leaves"); + public static final Key ACACIA_LEAVES = Key.of("minecraft:acacia_leaves"); + public static final Key DARK_OAK_LEAVES = Key.of("minecraft:dark_oak_leaves"); + public static final Key MANGROVE_LEAVES = Key.of("minecraft:mangrove_leaves"); + public static final Key CHERRY_LEAVES = Key.of("minecraft:cherry_leaves"); + public static final Key PALE_OAK_LEAVES = Key.of("minecraft:pale_oak_leaves"); + public static final Key AZALEA_LEAVES = Key.of("minecraft:azalea_leaves"); + public static final Key FLOWERING_AZALEA_LEAVES = Key.of("minecraft:flowering_azalea_leaves"); + public static final List WOODEN_TRAPDOORS = List.of(OAK_TRAPDOOR, SPRUCE_TRAPDOOR, BIRCH_TRAPDOOR, ACACIA_TRAPDOOR, PALE_OAK_TRAPDOOR, DARK_OAK_TRAPDOOR, MANGROVE_TRAPDOOR, JUNGLE_TRAPDOOR); public static final List CHERRY_TRAPDOORS = List.of(CHERRY_TRAPDOOR); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java index eaa50da56..83c34a1f4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java @@ -18,7 +18,7 @@ public class BlockStateHolder { this.propertyMap = new Reference2ObjectArrayMap<>(propertyMap); } - public Holder owner() { + public Holder.Reference owner() { return this.owner; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java index 846900088..0b19c2ee3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java @@ -9,4 +9,10 @@ public interface BlockStateWrapper { int registryId(); Key ownerId(); + + T getProperty(String propertyName); + + boolean hasProperty(String propertyName); + + String getAsString(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/StatePropertyAccessor.java b/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java similarity index 83% rename from core/src/main/java/net/momirealms/craftengine/core/block/state/StatePropertyAccessor.java rename to core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java index a69d4e24e..3e1a46e3f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/state/StatePropertyAccessor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.block.state; +package net.momirealms.craftengine.core.block; import java.util.Collection; 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 42753ec45..641c71a72 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 @@ -1,6 +1,6 @@ package net.momirealms.craftengine.core.block.properties; -import net.momirealms.craftengine.core.block.state.properties.*; +import net.momirealms.craftengine.core.block.properties.type.*; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.registry.BuiltInRegistries; import net.momirealms.craftengine.core.registry.Registries; @@ -40,7 +40,6 @@ public final class Properties { register(SLAB_TYPE, new EnumProperty.Factory<>(SlabType.class)); register(SOFA_SHAPE, new EnumProperty.Factory<>(SofaShape.class)); register(ANCHOR_TYPE, new EnumProperty.Factory<>(AnchorType.class)); - } public static void register(Key key, PropertyFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/AnchorType.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/AnchorType.java new file mode 100644 index 000000000..26e95f0a5 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/AnchorType.java @@ -0,0 +1,7 @@ +package net.momirealms.craftengine.core.block.properties.type; + +public enum AnchorType { + FLOOR, + WALL, + CEILING +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoorHinge.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoorHinge.java new file mode 100644 index 000000000..16ef73e49 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoorHinge.java @@ -0,0 +1,5 @@ +package net.momirealms.craftengine.core.block.properties.type; + +public enum DoorHinge { + LEFT, RIGHT +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoubleBlockHalf.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoubleBlockHalf.java new file mode 100644 index 000000000..1823e76dd --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/DoubleBlockHalf.java @@ -0,0 +1,5 @@ +package net.momirealms.craftengine.core.block.properties.type; + +public enum DoubleBlockHalf { + UPPER, LOWER +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SingleBlockHalf.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SingleBlockHalf.java new file mode 100644 index 000000000..04cee6405 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SingleBlockHalf.java @@ -0,0 +1,5 @@ +package net.momirealms.craftengine.core.block.properties.type; + +public enum SingleBlockHalf { + TOP, BOTTOM +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SlabType.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SlabType.java new file mode 100644 index 000000000..2f1d2e1e5 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SlabType.java @@ -0,0 +1,7 @@ +package net.momirealms.craftengine.core.block.properties.type; + +public enum SlabType { + TOP, + BOTTOM, + DOUBLE +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SofaShape.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SofaShape.java similarity index 53% rename from core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SofaShape.java rename to core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SofaShape.java index a9d717dcb..82ef28632 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SofaShape.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/SofaShape.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.block.state.properties; +package net.momirealms.craftengine.core.block.properties.type; public enum SofaShape { STRAIGHT, diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/StairsShape.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/StairsShape.java similarity index 62% rename from core/src/main/java/net/momirealms/craftengine/core/block/state/properties/StairsShape.java rename to core/src/main/java/net/momirealms/craftengine/core/block/properties/type/StairsShape.java index b0cac6526..4d8616818 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/StairsShape.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/type/StairsShape.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.block.state.properties; +package net.momirealms.craftengine.core.block.properties.type; public enum StairsShape { STRAIGHT, diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AnchorType.java b/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AnchorType.java deleted file mode 100644 index 65bec0f74..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/AnchorType.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.momirealms.craftengine.core.block.state.properties; - -public enum AnchorType { - FLOOR, - WALL, - CEILING -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/DoorHinge.java b/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/DoorHinge.java deleted file mode 100644 index 811514a63..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/DoorHinge.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.momirealms.craftengine.core.block.state.properties; - -public enum DoorHinge { - LEFT, RIGHT -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/DoubleBlockHalf.java b/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/DoubleBlockHalf.java deleted file mode 100644 index 1891b3de8..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/DoubleBlockHalf.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.momirealms.craftengine.core.block.state.properties; - -public enum DoubleBlockHalf { - UPPER, LOWER -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SingleBlockHalf.java b/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SingleBlockHalf.java deleted file mode 100644 index c5b3b83e8..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SingleBlockHalf.java +++ /dev/null @@ -1,5 +0,0 @@ -package net.momirealms.craftengine.core.block.state.properties; - -public enum SingleBlockHalf { - TOP, BOTTOM -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SlabType.java b/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SlabType.java deleted file mode 100644 index 09f4fbbfb..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/state/properties/SlabType.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.momirealms.craftengine.core.block.state.properties; - -public enum SlabType { - TOP, - BOTTOM, - DOUBLE -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 3fbeefb07..80ec3ace5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -5,7 +5,7 @@ import net.momirealms.craftengine.core.entity.player.Player; 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.cache.IdAllocator; +import net.momirealms.craftengine.core.pack.allocator.IdAllocator; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.plugin.config.ConfigParser; 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 a4c0164c3..e6b46ea9d 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 @@ -14,7 +14,7 @@ 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.cache.IdAllocator; +import net.momirealms.craftengine.core.pack.allocator.IdAllocator; 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; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateAllocator.java new file mode 100644 index 000000000..5669d0b27 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateAllocator.java @@ -0,0 +1,33 @@ +package net.momirealms.craftengine.core.pack.allocator; + +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class BlockStateAllocator { + private final List blockStates = new ArrayList<>(); + private int pointer = 0; + private int max = -1; + + public void addCandidate(BlockStateCandidate state) { + this.blockStates.add(state); + this.max = this.blockStates.size() - 1; + } + + @Nullable + public BlockStateCandidate findNext() { + while (this.pointer < this.max) { + final BlockStateCandidate state = this.blockStates.get(this.pointer); + if (!state.isUsed()) { + return state; + } + this.pointer++; + } + return null; + } + + public void processPendingAllocations() { + + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateCandidate.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateCandidate.java new file mode 100644 index 000000000..abcfdfbba --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateCandidate.java @@ -0,0 +1,24 @@ +package net.momirealms.craftengine.core.pack.allocator; + +import net.momirealms.craftengine.core.block.BlockStateWrapper; + +public class BlockStateCandidate { + private final BlockStateWrapper blockState; + private boolean used = false; + + public BlockStateCandidate(BlockStateWrapper blockState) { + this.blockState = blockState; + } + + public void setUsed() { + this.used = true; + } + + public boolean isUsed() { + return used; + } + + public BlockStateWrapper blockState() { + return blockState; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java similarity index 99% rename from core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java rename to core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java index 5977120db..47c5e6bd3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/cache/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java @@ -1,4 +1,4 @@ -package net.momirealms.craftengine.core.pack.cache; +package net.momirealms.craftengine.core.pack.allocator; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java index e5ce7b198..41db9e150 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/condition/MatchBlockPropertyCondition.java @@ -2,8 +2,8 @@ package net.momirealms.craftengine.core.plugin.context.condition; import net.momirealms.craftengine.core.block.CustomBlock; import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.block.StatePropertyAccessor; import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.block.state.StatePropertyAccessor; 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/locale/I18NData.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java index a87b62c10..4d8689096 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/I18NData.java @@ -26,7 +26,7 @@ public class I18NData { if (blockOptional.isPresent()) { List states = blockOptional.get().variantProvider().states(); if (states.size() == 1) { - return List.of("block." + stateToRealBlockId(states.get(0))); + return List.of("block." + stateToRealBlockId(states.getFirst())); } else { ArrayList processed = new ArrayList<>(); for (ImmutableBlockState state : states) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index b4e249748..35b1026ef 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -2,16 +2,12 @@ package net.momirealms.craftengine.core.plugin.locale; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.core.block.AbstractBlockManager; -import net.momirealms.craftengine.core.font.FontManager; -import net.momirealms.craftengine.core.font.OffsetFont; 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.Plugin; import net.momirealms.craftengine.core.plugin.PluginProperties; import net.momirealms.craftengine.core.plugin.config.*; -import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; import net.momirealms.craftengine.core.plugin.text.minimessage.ImageTag; import net.momirealms.craftengine.core.plugin.text.minimessage.IndexedArgumentTag; import net.momirealms.craftengine.core.plugin.text.minimessage.ShiftTag; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index bc134b433..c17579e65 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -1,15 +1,11 @@ package net.momirealms.craftengine.core.util; import com.google.gson.JsonElement; -import net.kyori.adventure.audience.Audience; -import net.kyori.adventure.key.Key; -import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.ComponentIteratorType; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextReplacementConfig; import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.internal.parser.TokenParser; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import net.kyori.adventure.text.serializer.json.JSONOptions; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java index 3f069b8ec..08a9155e2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.core.util; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import java.util.regex.Pattern; import java.util.stream.IntStream; public class CharacterUtils { diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/ExistingBlock.java b/core/src/main/java/net/momirealms/craftengine/core/world/ExistingBlock.java index 947bc664d..d6fac39cf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/ExistingBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/ExistingBlock.java @@ -3,7 +3,7 @@ package net.momirealms.craftengine.core.world; 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.state.StatePropertyAccessor; +import net.momirealms.craftengine.core.block.StatePropertyAccessor; import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Key; import org.jetbrains.annotations.NotNull; diff --git a/gradle.properties b/gradle.properties index 604850d98..1de766a2f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.97 +nms_helper_version=1.0.98 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5 From 48bdf5f4e0505778ae45df136af238b8d6525590 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 29 Sep 2025 19:49:27 +0800 Subject: [PATCH 089/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=E9=85=8D=E7=BD=AE=E6=9C=AA=E5=8A=A0?= =?UTF-8?q?=E8=BD=BD=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../advancement/BukkitAdvancementManager.java | 2 +- .../bukkit/block/BukkitBlockManager.java | 40 ---------- .../block/BukkitCustomBlockStateWrapper.java | 2 +- .../bukkit/loot/BukkitVanillaLootManager.java | 2 +- common-files/src/main/resources/config.yml | 66 +++++++++++----- .../default/configuration/templates.yml | 2 +- .../core/block/AbstractBlockManager.java | 16 ++-- .../core/block/AbstractBlockStateWrapper.java | 5 ++ .../core/block/AbstractCustomBlock.java | 4 +- .../core/block/BlockStateHolder.java | 2 +- .../furniture/AbstractFurnitureManager.java | 4 +- .../core/font/AbstractFontManager.java | 18 +++-- .../core/item/AbstractItemManager.java | 4 +- .../item/recipe/AbstractRecipeManager.java | 2 +- .../core/pack/AbstractPackManager.java | 79 +++---------------- .../core/pack/LoadingSequence.java | 1 + .../plugin/config/AbstractConfigParser.java | 32 ++++++++ .../core/plugin/config/ConfigParser.java | 7 ++ .../plugin/config/IdObjectConfigParser.java | 22 +++++- .../plugin/config/IdSectionConfigParser.java | 38 ++++++++- .../plugin/config/SectionConfigParser.java | 16 +++- .../config/template/TemplateManagerImpl.java | 2 +- .../plugin/context/GlobalVariableManager.java | 2 +- .../gui/category/ItemBrowserManagerImpl.java | 2 +- .../plugin/locale/TranslationManagerImpl.java | 4 +- .../core/sound/AbstractSoundManager.java | 6 +- 26 files changed, 212 insertions(+), 168 deletions(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/config/AbstractConfigParser.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java index ee34b3993..e42a03083 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/advancement/BukkitAdvancementManager.java @@ -106,7 +106,7 @@ public class BukkitAdvancementManager extends AbstractAdvancementManager { } } - public class AdvancementParser implements IdSectionConfigParser { + public class AdvancementParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"advancements", "advancement"}; @Override 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 304156691..36c421336 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 @@ -75,7 +75,6 @@ public final class BukkitBlockManager extends AbstractBlockManager { public void init() { this.initMirrorRegistry(); this.initFireBlock(); - this.initVanillaBlockSettings(); this.deceiveBukkitRegistry(); this.markVanillaNoteBlocks(); Arrays.fill(this.immutableBlockStates, EmptyBlock.INSTANCE.defaultState()); @@ -94,7 +93,6 @@ public final class BukkitBlockManager extends AbstractBlockManager { @Override public void unload() { super.unload(); - Arrays.fill(this.blockStateMappings, -1); this.previousClientBoundTags = this.clientBoundTags; this.clientBoundTags = new HashMap<>(); for (DelegatingBlock block : this.burnableBlocks) { @@ -221,44 +219,6 @@ public final class BukkitBlockManager extends AbstractBlockManager { } } - private void initVanillaBlockSettings() { - try { - for (int i = 0; i < this.vanillaBlockStateCount; i++) { - Object blockState = BlockStateUtils.idToBlockState(i); - // 确保缓存已被激活 - CoreReflections.method$BlockStateBase$initCache.invoke(blockState); - BlockSettings settings = BlockSettings.of() - .pushReaction(PushReaction.VALUES[((Enum) CoreReflections.field$BlockStateBase$pushReaction.get(blockState)).ordinal()]) - .mapColor(MapColor.get(CoreReflections.field$MapColor$id.getInt(CoreReflections.field$BlockStateBase$mapColor.get(blockState)))) - .canOcclude(FastNMS.INSTANCE.method$BlockStateBase$canOcclude(blockState) ? Tristate.TRUE : Tristate.FALSE) - .isRandomlyTicking(CoreReflections.field$BlockStateBase$isRandomlyTicking.getBoolean(blockState)) - .hardness(CoreReflections.field$BlockStateBase$hardness.getFloat(blockState)) - .replaceable(CoreReflections.field$BlockStateBase$replaceable.getBoolean(blockState)) - .burnable(CoreReflections.field$BlockStateBase$burnable.getBoolean(blockState)) - .luminance(CoreReflections.field$BlockStateBase$lightEmission.getInt(blockState)) - .instrument(Instrument.VALUES[((Enum) CoreReflections.field$BlockStateBase$instrument.get(blockState)).ordinal()]) - .pushReaction(PushReaction.VALUES[((Enum) CoreReflections.field$BlockStateBase$pushReaction.get(blockState)).ordinal()]); - Object block = BlockStateUtils.getBlockOwner(blockState); - settings.resistance(CoreReflections.field$BlockBehaviour$explosionResistance.getFloat(block)) - .friction(CoreReflections.field$BlockBehaviour$friction.getFloat(block)) - .speedFactor(CoreReflections.field$BlockBehaviour$speedFactor.getFloat(block)) - .jumpFactor(CoreReflections.field$BlockBehaviour$jumpFactor.getFloat(block)) - .sounds(toBlockSounds(CoreReflections.field$BlockBehaviour$soundType.get(block))); - if (VersionHelper.isOrAbove1_21_2()) { - settings.blockLight(CoreReflections.field$BlockStateBase$lightBlock.getInt(blockState)); - settings.propagatesSkylightDown(CoreReflections.field$BlockStateBase$propagatesSkylightDown.getBoolean(blockState) ? Tristate.TRUE : Tristate.FALSE); - } else { - Object cache = CoreReflections.field$BlockStateBase$cache.get(blockState); - settings.blockLight(CoreReflections.field$BlockStateBase$Cache$lightBlock.getInt(cache)); - settings.propagatesSkylightDown(CoreReflections.field$BlockStateBase$Cache$propagatesSkylightDown.getBoolean(cache) ? Tristate.TRUE : Tristate.FALSE); - } - this.vanillaBlockSettings[i] = settings; - } - } catch (Exception e) { - this.plugin.logger().warn("Failed to initialize vanilla block settings", e); - } - } - @Override protected void applyPlatformSettings(ImmutableBlockState state) { DelegatingBlockState nmsState = (DelegatingBlockState) state.customBlockState().literalObject(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java index f67d21749..f336c1cbb 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java @@ -16,7 +16,7 @@ public class BukkitCustomBlockStateWrapper extends AbstractBlockStateWrapper { @Override public Key ownerId() { - return getImmutableBlockState().map(state -> state.owner().key().location()).orElseGet(() -> BlockStateUtils.getBlockOwnerIdFromState(super.blockState)); + return getImmutableBlockState().map(state -> state.owner().value().id()).orElseGet(() -> BlockStateUtils.getBlockOwnerIdFromState(super.blockState)); } @SuppressWarnings("unchecked") 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 805808e92..d38e58a24 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 @@ -91,7 +91,7 @@ public class BukkitVanillaLootManager extends AbstractVanillaLootManager impleme return this.vanillaLootParser; } - public class VanillaLootParser implements IdSectionConfigParser { + public class VanillaLootParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"vanilla-loots", "vanilla-loot"}; @Override diff --git a/common-files/src/main/resources/config.yml b/common-files/src/main/resources/config.yml index 1ba1c55a3..ee7b4e559 100644 --- a/common-files/src/main/resources/config.yml +++ b/common-files/src/main/resources/config.yml @@ -145,14 +145,36 @@ resource-pack: item: # [Premium Exclusive] - # Make custom-model-data and item-model clientside by default + # Makes custom-model-data and item-model client-side by default. + # + # This provides several benefits. For example, you can update model values + # dynamically without causing inconsistencies for players' existing items. + # + # The main drawback is that plugins relying on custom-model-data for item + # identification will not work correctly, as this data is not present in + # the server-side item stack. + # + # You can override this global setting per item using the + # client-bound-model option. client-bound-model: true - # Add a tag on custom name and lore + # When enabled (recommended), this option adds both custom-model-data + # and an item-model to optimize client-side rendering. + # + # If disabled, the system falls back to using only custom-model-data. + # You can override this behavior by setting the item-model option + # on a per-item basis. + # + # This option only works if your resource pack supports 1.21.1 or below + always-use-item-model: true + # Since Minecraft renders lore text in italics by default, you can + # optionally prefix any lore with to remove the italic formatting. non-italic-tag: false - # Determines when to trigger the item updater - # This feature may incur some performance overhead. Please do not enable it unless necessary. - # Correct use case: When you designed incorrect weapon attributes and need to update the values for items already held by players. - # Wrong use case: When you want to update an item's name and lore to a newer version (In this case you should use client-bound-data instead of the item updater) + # Defines the trigger condition for the item updater. + # + # Warning: This operation is performance-intensive. Enable only if needed. + # + # Purpose: Reserved for correcting faults on existing player items. + # Not intended for updating names/lore; use 'client-bound-data' for those changes. update-triggers: click-in-inventory: false # this option won't work for players in creative mode drop: false @@ -175,29 +197,31 @@ equipment: humanoid-leggings: minecraft:trims/entity/humanoid_leggings/chainmail block: - # This decides the amount of real blocks on serverside. Requires a restart to apply. - serverside-blocks: 2025 + # This decides the amount of real blocks on serverside. You should only consider increasing this value when your server state is insufficient. + # It is recommended to increase it by 500 each time. This option requires a restart to apply. + serverside-blocks: 2000 # Enables the sound system, which prevents the client from hearing some non-custom block sounds and improves the client experience. sound-system: enable: true - # In Adventure Mode, players need the correct tool to break custom blocks. - # Vanilla clients DO NOT recognize custom block IDs (e.g., craftengine:note_block_0). + # Adventure mode requires correct tools to break custom blocks. + # Vanilla clients cannot recognize custom block IDs (e.g., craftengine:custom_100). # - # - When ENABLED: - # - Players can break custom blocks if their tools can mine their VANILLA EQUIVALENTS. - # Example: A tool for "note_block" can break "craftengine:note_block_0". + # ENABLED: + # - Tools that can break vanilla equivalents also break custom variants. + # Example: A "note_block" tool breaks custom blocks based on note blocks # - # - When DISABLED: - # ⚠️ WARNING: - # - Server MUST list ACTUAL CUSTOM BLOCK IDs in item's `can_break` component. - # - Sending custom IDs (e.g., craftengine:note_block_0) to vanilla clients WILL CRASH THEM! - # ✅ Solution: - # - Use `client-bound-data` to safely sync custom block data to clients. + # DISABLED: + # ⚠️ Server MUST specify SERVERSIDE CUSTOM BLOCK IDs in item's `can_break`. + # ⚠️ Sending custom block IDs to vanilla clients WILL CAUSE CRASHES! + # ✅ Recommended: Use `client-bound-data` for safe client synchronization. simplify-adventure-break-check: false # Similar to the option above, but designed for block placement simplify-adventure-place-check: false - # Whether plugin should predict the next block to break - # This can help improve mining experience to some extent at the cost of performance + # Uses raycasting to predict the player's next block break, + # enabling pre-calculation of mining speed attributes. + + # Enables block break prediction. + # Enhances mining responsiveness with moderate performance cost. predict-breaking: enable: false interval: 10 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 044ccbf3a..5912b31f5 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -933,7 +933,7 @@ templates#block_states: resistance: 1200.0 burnable: false fluid-state: water - distance=7: + distance=7,persistent=false: settings: is-randomly-ticking: true # trapdoor block diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index ef7d9d282..5d5b66231 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -19,8 +19,8 @@ import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.pack.ResourceLocation; import net.momirealms.craftengine.core.pack.allocator.BlockStateAllocator; -import net.momirealms.craftengine.core.pack.allocator.IdAllocator; import net.momirealms.craftengine.core.pack.allocator.BlockStateCandidate; +import net.momirealms.craftengine.core.pack.allocator.IdAllocator; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -80,8 +80,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final Object[] customBlockHolders; // 自定义状态列表,会随着重载变化 protected final ImmutableBlockState[] immutableBlockStates; - // 原版方块的属性缓存 - protected final BlockSettings[] vanillaBlockSettings; // 倒推缓存 protected final BlockStateCandidate[] reversedBlockStateArranger; // 临时存储哪些视觉方块被使用了 @@ -98,7 +96,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.customBlocks = new DelegatingBlock[customBlockCount]; this.customBlockHolders = new Object[customBlockCount]; this.customBlockStates = new DelegatingBlockState[customBlockCount]; - this.vanillaBlockSettings = new BlockSettings[vanillaBlockStateCount]; this.immutableBlockStates = new ImmutableBlockState[customBlockCount]; this.blockStateMappings = new int[customBlockCount + vanillaBlockStateCount]; this.reversedBlockStateArranger = new BlockStateCandidate[vanillaBlockStateCount]; @@ -236,7 +233,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem @NotNull Map>> events, @Nullable LootTable lootTable); - public class BlockStateMappingParser implements SectionConfigParser { + public class BlockStateMappingParser extends SectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"block-state-mappings", "block-state-mapping"}; @Override @@ -285,7 +282,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } - public class BlockParser implements IdSectionConfigParser { + public class BlockParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; private final IdAllocator internalIdAllocator; private final List pendingConfigSections = new ArrayList<>(); @@ -618,9 +615,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } // 拆分方块id与属性 - String blockState = blockStateWrapper.toString(); - Key blockId = Key.of(blockState.substring(blockState.indexOf('{') + 1, blockState.lastIndexOf('}'))); - String propertyNBT = blockState.substring(blockState.indexOf('[') + 1, blockState.lastIndexOf(']')); + String blockState = blockStateWrapper.getAsString(); + int firstIndex = blockState.indexOf('['); + Key blockId = firstIndex == -1 ? Key.of(blockState) : Key.of(blockState.substring(0, firstIndex)); + String propertyNBT = firstIndex == -1 ? "" : blockState.substring(firstIndex + 1, blockState.lastIndexOf(']')); // 结合variants JsonElement combinedVariant = GsonHelper.combine(variants); Map overrideMap = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java index fd3f67fbe..7ce0ad545 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java @@ -18,4 +18,9 @@ public abstract class AbstractBlockStateWrapper implements BlockStateWrapper { public int registryId() { return this.registryId; } + + @Override + public String toString() { + return this.blockState.toString(); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java index 298de8ccd..01e818042 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractCustomBlock.java @@ -19,6 +19,7 @@ import java.util.*; import java.util.function.BiFunction; public abstract class AbstractCustomBlock implements CustomBlock { + protected final Key id; protected final Holder.Reference holder; protected final BlockStateVariantProvider variantProvider; protected final BiFunction placementFunction; @@ -34,6 +35,7 @@ public abstract class AbstractCustomBlock implements CustomBlock { @NotNull Map>> events, @Nullable LootTable lootTable ) { + this.id = holder.key().location(); this.holder = holder; this.lootTable = lootTable; this.events = events; @@ -85,7 +87,7 @@ public abstract class AbstractCustomBlock implements CustomBlock { @NotNull @Override public final Key id() { - return this.holder.key().location(); + return this.id; } public void setBehavior(@Nullable BlockBehavior behavior) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java index 83c34a1f4..eaa50da56 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java @@ -18,7 +18,7 @@ public class BlockStateHolder { this.propertyMap = new Reference2ObjectArrayMap<>(propertyMap); } - public Holder.Reference owner() { + public Holder owner() { return this.owner; } 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 008d83b52..8a2a4ad05 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 @@ -76,7 +76,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { protected abstract CustomFurniture.Builder furnitureBuilder(); - public class FurnitureParser implements IdSectionConfigParser { + public class FurnitureParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] { "furniture" }; private final List pendingConfigSections = new ArrayList<>(); @@ -110,7 +110,7 @@ public abstract class AbstractFurnitureManager implements FurnitureManager { @SuppressWarnings("unchecked") @Override public void parseSection(Pack pack, Path path, String node, Key id, Map section) { - if (byId.containsKey(id)) { + if (AbstractFurnitureManager.this.byId.containsKey(id)) { throw new LocalizedResourceConfigException("warning.config.furniture.duplicate"); } EnumMap placements = new EnumMap<>(AnchorType.class); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 80ec3ace5..f8ed7e7c3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -232,7 +232,7 @@ public abstract class AbstractFontManager implements FontManager { emoji.content(), PlayerOptionalContext.of(player, ContextHolder.builder() .withOptionalParameter(EmojiParameters.EMOJI, emoji.emojiImage()) - .withParameter(EmojiParameters.KEYWORD, emoji.keywords().get(0)) + .withParameter(EmojiParameters.KEYWORD, emoji.keywords().getFirst()) ).tagResolvers()) ); if (emojis.size() >= maxTimes) break; @@ -390,7 +390,7 @@ public abstract class AbstractFontManager implements FontManager { return this.fonts.computeIfAbsent(key, Font::new); } - public class EmojiParser implements IdSectionConfigParser { + public class EmojiParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"emoji", "emojis"}; @Override @@ -457,7 +457,7 @@ public abstract class AbstractFontManager implements FontManager { } } - public class ImageParser implements IdSectionConfigParser { + public class ImageParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"images", "image"}; private final Map idAllocators = new HashMap<>(); @@ -577,7 +577,11 @@ public abstract class AbstractFontManager implements FontManager { codepoints = CharacterUtils.charsToCodePoints(charString.toCharArray()); } for (int j = 0; j < codepoints.length; j++) { - futureCodepoints.add(allocator.assignFixedId(id.asString() + ":" + i + ":" + j, codepoints[j])); + if (codepoints[j] == 0) { + futureCodepoints.add(CompletableFuture.completedFuture(0)); + } else { + futureCodepoints.add(allocator.assignFixedId(id.asString() + ":" + i + ":" + j, codepoints[j])); + } } if (tempColumns == -1) { tempColumns = codepoints.length; @@ -607,7 +611,11 @@ public abstract class AbstractFontManager implements FontManager { } columns = codepoints.length; for (int i = 0; i < codepoints.length; i++) { - futureCodepoints.add(allocator.assignFixedId(id.asString() + ":0:" + i, codepoints[i])); + if (codepoints[i] == 0) { + futureCodepoints.add(CompletableFuture.completedFuture(0)); + } else { + futureCodepoints.add(allocator.assignFixedId(id.asString() + ":0:" + i, codepoints[i])); + } } } } 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 e6b46ea9d..b1d0539ed 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 @@ -270,7 +270,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected abstract void registerArmorTrimPattern(Collection equipments); - public class EquipmentParser implements IdSectionConfigParser { + public class EquipmentParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"equipments", "equipment"}; @Override @@ -313,7 +313,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } - public class ItemParser implements IdSectionConfigParser { + public class ItemParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"items", "item"}; private final Map idAllocators = new HashMap<>(); 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 6a9fc4273..22c095387 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 @@ -121,7 +121,7 @@ public abstract class AbstractRecipeManager implements RecipeManager { return true; } - public class RecipeParser implements IdSectionConfigParser { + public class RecipeParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"recipes", "recipe"}; @Override 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 c0b51bace..c4ed3e352 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 @@ -86,6 +86,7 @@ public abstract class AbstractPackManager implements PackManager { private final BiConsumer generationEventDispatcher; private final Map loadedPacks = new HashMap<>(); private final Map sectionParsers = new HashMap<>(); + private final TreeSet sortedParsers = new TreeSet<>(); private final JsonObject vanillaAtlas; private Map cachedConfigFiles = Collections.emptyMap(); private Map cachedAssetFiles = Collections.emptyMap(); @@ -293,6 +294,7 @@ public abstract class AbstractPackManager implements PackManager { for (String id : parser.sectionId()) { this.sectionParsers.put(id, parser); } + this.sortedParsers.add(parser); return true; } @@ -548,10 +550,9 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/models/block/custom/fence_side.json"); } - private TreeMap> updateCachedConfigFiles() { - TreeMap> cachedConfigs = new TreeMap<>(); + private void updateCachedConfigFiles() { Map previousFiles = this.cachedConfigFiles; - this.cachedConfigFiles = new Object2ObjectOpenHashMap<>(32); + this.cachedConfigFiles = new HashMap<>(64, 0.5f); for (Pack pack : loadedPacks()) { if (!pack.enabled()) continue; Path configurationFolderPath = pack.configurationFolder(); @@ -596,9 +597,7 @@ public abstract class AbstractPackManager implements PackManager { } } for (Map.Entry entry : cachedFile.config().entrySet()) { - processConfigEntry(entry, path, cachedFile.pack(), (p, c) -> - cachedConfigs.computeIfAbsent(p, k -> new ArrayList<>()).add(c) - ); + processConfigEntry(entry, path, cachedFile.pack(), ConfigParser::addConfig); } } return FileVisitResult.CONTINUE; @@ -608,76 +607,20 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().severe("Error while reading config file", e); } } - return cachedConfigs; } private void loadResourceConfigs(Predicate predicate) { long o1 = System.nanoTime(); - TreeMap> cachedConfigs = this.updateCachedConfigFiles(); + this.updateCachedConfigFiles(); long o2 = System.nanoTime(); this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); - for (Map.Entry> entry : cachedConfigs.entrySet()) { - ConfigParser parser = entry.getKey(); + for (ConfigParser parser : this.sortedParsers) { if (!predicate.test(parser)) continue; long t1 = System.nanoTime(); parser.preProcess(); - switch (parser) { - case SectionConfigParser configParser -> { - for (CachedConfigSection cached : entry.getValue()) { - ResourceConfigUtils.runCatching( - cached.filePath(), - cached.prefix(), - () -> configParser.parseSection(cached.pack(), cached.filePath(), cached.config()), - () -> GsonHelper.get().toJson(cached.config()) - ); - } - } - case IdObjectConfigParser configParser -> { - for (CachedConfigSection cached : entry.getValue()) { - for (Map.Entry configEntry : cached.config().entrySet()) { - String key = configEntry.getKey(); - Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); - String node = cached.prefix() + "." + key; - ResourceConfigUtils.runCatching( - cached.filePath(), - node, - () -> configParser.parseObject(cached.pack(), cached.filePath(), node, id, configEntry.getValue()), - () -> GsonHelper.get().toJson(configEntry.getValue()) - ); - } - } - } - case IdSectionConfigParser configParser -> { - for (CachedConfigSection cached : entry.getValue()) { - for (Map.Entry configEntry : cached.config().entrySet()) { - String key = configEntry.getKey(); - Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); - if (!(configEntry.getValue() instanceof Map section)) { - TranslationManager.instance().log("warning.config.structure.not_section", - cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); - continue; - } - Map config = castToMap(section, false); - if ((boolean) config.getOrDefault("debug", false)) { - this.plugin.logger().info(GsonHelper.get().toJson(this.plugin.templateManager().applyTemplates(id, config))); - } - if (!(boolean) config.getOrDefault("enable", true)) { - continue; - } - String node = cached.prefix() + "." + key; - ResourceConfigUtils.runCatching( - cached.filePath(), - node, - () -> configParser.parseSection(cached.pack(), cached.filePath(), node, id, MiscUtils.castToMap(this.plugin.templateManager().applyTemplates(id, config), false)), - () -> GsonHelper.get().toJson(section) - ); - } - } - } - default -> { - } - } + parser.loadAll(); parser.postProcess(); + parser.clear(); long t2 = System.nanoTime(); this.plugin.logger().info("Loaded " + parser.sectionId()[0] + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms"); } @@ -2252,9 +2195,9 @@ public abstract class AbstractPackManager implements PackManager { } private List>> updateCachedAssets(@NotNull PackCacheData cacheData, @Nullable FileSystem fs) throws IOException { - Map> conflictChecker = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size())); + Map> conflictChecker = new HashMap<>(Math.max(128, this.cachedAssetFiles.size()), 0.6f); Map previousFiles = this.cachedAssetFiles; - this.cachedAssetFiles = new Object2ObjectOpenHashMap<>(Math.max(128, this.cachedAssetFiles.size())); + this.cachedAssetFiles = new HashMap<>(Math.max(128, this.cachedAssetFiles.size()), 0.6f); List folders = new ArrayList<>(); folders.addAll(loadedPacks().stream() 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 46e3998aa..f8928a7ef 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 @@ -3,6 +3,7 @@ package net.momirealms.craftengine.core.pack; public final class LoadingSequence { private LoadingSequence() {} + // 模板第一位 public static final int TEMPLATE = 0; public static final int BLOCK_STATE_MAPPING = 10; public static final int GLOBAL_VAR = 20; diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/AbstractConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/AbstractConfigParser.java new file mode 100644 index 000000000..cbbc609fb --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/AbstractConfigParser.java @@ -0,0 +1,32 @@ +package net.momirealms.craftengine.core.plugin.config; + +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.momirealms.craftengine.core.pack.CachedConfigSection; + +public abstract class AbstractConfigParser implements ConfigParser { + protected final ObjectArrayList configStorage; + + public AbstractConfigParser() { + this.configStorage = new ObjectArrayList<>(); + } + + @Override + public void addConfig(CachedConfigSection section) { + this.configStorage.add(section); + } + + @Override + public void loadAll() { + Object[] elements = this.configStorage.elements(); + for (int i = 0, size = this.configStorage.size(); i < size; i++) { + parseSection((CachedConfigSection) elements[i]); + } + } + + @Override + public void clear() { + this.configStorage.clear(); + } + + protected abstract void parseSection(CachedConfigSection section); +} 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 48ba108f9..5fc06c91e 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 @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.plugin.config; +import net.momirealms.craftengine.core.pack.CachedConfigSection; import org.jetbrains.annotations.NotNull; public interface ConfigParser extends Comparable { @@ -18,4 +19,10 @@ public interface ConfigParser extends Comparable { default void preProcess() { } + + void addConfig(CachedConfigSection section); + + void loadAll(); + + void clear(); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java index 9238a31cc..2a7f49f8d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdObjectConfigParser.java @@ -1,13 +1,31 @@ package net.momirealms.craftengine.core.plugin.config; +import net.momirealms.craftengine.core.pack.CachedConfigSection; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.nio.file.Path; +import java.util.Map; -public interface IdObjectConfigParser extends ConfigParser { +public abstract class IdObjectConfigParser extends AbstractConfigParser { - default void parseObject(Pack pack, Path path, String node, Key id, Object object) throws LocalizedException { + @Override + protected void parseSection(CachedConfigSection cached) { + for (Map.Entry configEntry : cached.config().entrySet()) { + String key = configEntry.getKey(); + Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); + String node = cached.prefix() + "." + key; + ResourceConfigUtils.runCatching( + cached.filePath(), + node, + () -> parseObject(cached.pack(), cached.filePath(), node, id, configEntry.getValue()), + () -> GsonHelper.get().toJson(configEntry.getValue()) + ); + } } + + protected abstract void parseObject(Pack pack, Path path, String node, Key id, Object object) throws LocalizedException; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java index e14e42ba2..ff5828380 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/IdSectionConfigParser.java @@ -1,14 +1,48 @@ package net.momirealms.craftengine.core.plugin.config; +import net.momirealms.craftengine.core.pack.CachedConfigSection; import net.momirealms.craftengine.core.pack.Pack; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; +import net.momirealms.craftengine.core.util.GsonHelper; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.nio.file.Path; import java.util.Map; -public interface IdSectionConfigParser extends ConfigParser { +import static net.momirealms.craftengine.core.util.MiscUtils.castToMap; - default void parseSection(Pack pack, Path path, String node, Key id, Map section) throws LocalizedException { +public abstract class IdSectionConfigParser extends AbstractConfigParser { + + @Override + protected void parseSection(CachedConfigSection cached) { + for (Map.Entry configEntry : cached.config().entrySet()) { + String key = configEntry.getKey(); + Key id = Key.withDefaultNamespace(key, cached.pack().namespace()); + if (!(configEntry.getValue() instanceof Map section)) { + TranslationManager.instance().log("warning.config.structure.not_section", + cached.filePath().toString(), cached.prefix() + "." + key, configEntry.getValue().getClass().getSimpleName()); + continue; + } + Map config = castToMap(section, false); + if ((boolean) config.getOrDefault("debug", false)) { + CraftEngine.instance().logger().info(GsonHelper.get().toJson(CraftEngine.instance().templateManager().applyTemplates(id, config))); + } + if (!(boolean) config.getOrDefault("enable", true)) { + continue; + } + String node = cached.prefix() + "." + key; + ResourceConfigUtils.runCatching( + cached.filePath(), + node, + () -> parseSection(cached.pack(), cached.filePath(), node, id, MiscUtils.castToMap(CraftEngine.instance().templateManager().applyTemplates(id, config), false)), + () -> GsonHelper.get().toJson(section) + ); + } } + + protected abstract void parseSection(Pack pack, Path path, String node, Key id, Map section) throws LocalizedException; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/SectionConfigParser.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/SectionConfigParser.java index 871d1674f..626a9ffc8 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/SectionConfigParser.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/SectionConfigParser.java @@ -1,13 +1,25 @@ package net.momirealms.craftengine.core.plugin.config; +import net.momirealms.craftengine.core.pack.CachedConfigSection; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; +import net.momirealms.craftengine.core.util.GsonHelper; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.nio.file.Path; import java.util.Map; -public interface SectionConfigParser extends ConfigParser { +public abstract class SectionConfigParser extends AbstractConfigParser { - default void parseSection(Pack pack, Path path, Map section) throws LocalizedException { + @Override + protected void parseSection(CachedConfigSection cached) { + ResourceConfigUtils.runCatching( + cached.filePath(), + cached.prefix(), + () -> parseSection(cached.pack(), cached.filePath(), cached.config()), + () -> GsonHelper.get().toJson(cached.config()) + ); } + + protected abstract void parseSection(Pack pack, Path path, Map section) throws LocalizedException; } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java index 33c2622f4..3356a760f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -37,7 +37,7 @@ public class TemplateManagerImpl implements TemplateManager { return this.templateParser; } - public class TemplateParser implements IdObjectConfigParser { + public class TemplateParser extends IdObjectConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"templates", "template"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java index ee677e725..078a8c600 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/GlobalVariableManager.java @@ -36,7 +36,7 @@ public class GlobalVariableManager implements Manageable { return this.parser; } - public class GlobalVariableParser implements IdObjectConfigParser { + public class GlobalVariableParser extends IdObjectConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"global-variables", "global-variable"}; @Override 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 ed34e31a9..b4d6d30f4 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 @@ -96,7 +96,7 @@ public class ItemBrowserManagerImpl implements ItemBrowserManager { return Optional.ofNullable(this.byId.get(key)); } - public class CategoryParser implements IdSectionConfigParser { + public class CategoryParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"categories", "category"}; @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java index 35b1026ef..98db56742 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/TranslationManagerImpl.java @@ -246,7 +246,7 @@ public class TranslationManagerImpl implements TranslationManager { } } - public class I18NParser implements IdSectionConfigParser { + public class I18NParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"i18n", "internationalization", "translation", "translations"}; @Override @@ -277,7 +277,7 @@ public class TranslationManagerImpl implements TranslationManager { } } - public class LangParser implements IdSectionConfigParser { + public class LangParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"lang", "language", "languages"}; private final Function langProcessor = s -> { Component deserialize = AdventureHelper.miniMessage().deserialize(AdventureHelper.legacyToMiniMessage(s), ShiftTag.INSTANCE, ImageTag.INSTANCE); 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 2e6def245..3c5886417 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 @@ -66,8 +66,8 @@ public abstract class AbstractSoundManager implements SoundManager { protected abstract void registerSounds(Collection sounds); - public class SongParser implements IdSectionConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox_songs", "jukebox_song", "jukebox-songs", "jukebox-song"}; + public class SongParser extends IdSectionConfigParser { + public static final String[] CONFIG_SECTION_NAME = new String[] {"jukebox-songs", "jukebox-song", "jukebox_songs", "jukebox_song"}; @Override public int loadingSequence() { @@ -93,7 +93,7 @@ public abstract class AbstractSoundManager implements SoundManager { } } - public class SoundParser implements IdSectionConfigParser { + public class SoundParser extends IdSectionConfigParser { public static final String[] CONFIG_SECTION_NAME = new String[] {"sounds", "sound"}; @Override From a85b94392ee9945c645bc10e2e466467865d26de Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Tue, 30 Sep 2025 01:14:40 +0800 Subject: [PATCH 090/125] =?UTF-8?q?=E5=A4=96=E8=A7=82=E6=96=B9=E5=9D=97?= =?UTF-8?q?=E5=88=86=E9=85=8D=20=E6=9C=AA=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/api/BukkitAdaptors.java | 48 ++- .../bukkit/api/CraftEngineImages.java | 40 +++ .../bukkit/block/BukkitBlockManager.java | 17 +- .../bukkit/font/BukkitFontManager.java | 6 + .../bukkit/plugin/BukkitCraftEngine.java | 5 + .../plugin/command/BukkitCommandManager.java | 3 +- .../feature/DebugCleanCacheCommand.java | 84 +++++ common-files/src/main/resources/commands.yml | 7 + .../configuration/blocks/chessboard_block.yml | 8 +- .../configuration/blocks/chinese_lantern.yml | 2 +- .../configuration/blocks/copper_coil.yml | 4 +- .../blocks/ender_pearl_flower.yml | 6 +- .../configuration/blocks/fairy_flower.yml | 2 +- .../configuration/blocks/flame_cane.yml | 2 +- .../configuration/blocks/gunpowder_block.yml | 4 +- .../configuration/blocks/palm_tree.yml | 8 +- .../default/configuration/blocks/pebble.yml | 6 +- .../default/configuration/blocks/reed.yml | 2 +- .../configuration/blocks/safe_block.yml | 16 +- .../configuration/blocks/topaz_ore.yml | 2 +- .../default/configuration/templates.yml | 246 +------------ .../src/main/resources/translations/en.yml | 2 + .../core/block/AbstractBlockManager.java | 332 +++++++++++------- .../core/block/AbstractBlockStateWrapper.java | 12 + .../core/block/AutoStateGroup.java | 65 +++- .../craftengine/core/block/BlockKeys.java | 10 + .../core/block/BlockStateWrapper.java | 8 +- .../core/font/AbstractFontManager.java | 10 + .../craftengine/core/font/FontManager.java | 4 + .../core/item/AbstractItemManager.java | 8 + .../core/pack/AbstractPackManager.java | 10 +- .../pack/allocator/BlockStateAllocator.java | 33 -- .../core/pack/allocator/IdAllocator.java | 6 +- .../allocator/VisualBlockStateAllocator.java | 152 ++++++++ .../allocator/cache/AllocationCacheFile.java | 62 ++++ .../allocator/cache/CacheFileStorage.java | 98 ++++++ .../pack/allocator/cache/CacheFileType.java | 39 ++ .../pack/allocator/cache/CacheSerializer.java | 51 +++ .../pack/allocator/cache/CacheStorage.java | 32 ++ 39 files changed, 975 insertions(+), 477 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineImages.java create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateAllocator.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/AllocationCacheFile.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheFileStorage.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheFileType.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheSerializer.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheStorage.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java index 6dcd0167a..c667f832e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/BukkitAdaptors.java @@ -3,37 +3,63 @@ package net.momirealms.craftengine.bukkit.api; import net.momirealms.craftengine.bukkit.entity.BukkitEntity; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.LocationUtils; import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock; import net.momirealms.craftengine.bukkit.world.BukkitWorld; -import net.momirealms.craftengine.core.world.WorldPosition; -import org.bukkit.Location; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; public final class BukkitAdaptors { private BukkitAdaptors() {} - public static BukkitServerPlayer adapt(final Player player) { + /** + * Adapts a Bukkit Player to a CraftEngine BukkitServerPlayer. + * This provides access to CraftEngine-specific player functionality and data. + * + * @param player the Bukkit Player to adapt, must not be null + * @return a non-null BukkitServerPlayer instance wrapping the provided player + */ + @NotNull + public static BukkitServerPlayer adapt(@NotNull final Player player) { return BukkitCraftEngine.instance().adapt(player); } - public static BukkitWorld adapt(final World world) { + /** + * Adapts a Bukkit World to a CraftEngine BukkitWorld. + * This enables CraftEngine world operations on Bukkit world instances. + * + * @param world the Bukkit World to adapt, must not be null + * @return a non-null BukkitWorld instance wrapping the provided world + */ + @NotNull + public static BukkitWorld adapt(@NotNull final World world) { return new BukkitWorld(world); } - public static BukkitEntity adapt(final Entity entity) { + /** + * Adapts a Bukkit Entity to a CraftEngine BukkitEntity. + * This provides CraftEngine entity functionality for Bukkit entities. + * + * @param entity the Bukkit Entity to adapt, must not be null + * @return a non-null BukkitEntity instance wrapping the provided entity + */ + @NotNull + public static BukkitEntity adapt(@NotNull final Entity entity) { return new BukkitEntity(entity); } - public static BukkitExistingBlock adapt(final Block block) { + /** + * Adapts a Bukkit Block to a CraftEngine BukkitExistingBlock. + * This enables CraftEngine block operations on Bukkit block instances. + * + * @param block the Bukkit Block to adapt, must not be null + * @return a non-null BukkitExistingBlock instance wrapping the provided block + */ + @NotNull + public static BukkitExistingBlock adapt(@NotNull final Block block) { return new BukkitExistingBlock(block); } - - public static Location toLocation(WorldPosition position) { - return LocationUtils.toLocation(position); - } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineImages.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineImages.java new file mode 100644 index 000000000..3a420339f --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/api/CraftEngineImages.java @@ -0,0 +1,40 @@ +package net.momirealms.craftengine.bukkit.api; + +import net.momirealms.craftengine.bukkit.font.BukkitFontManager; +import net.momirealms.craftengine.core.font.BitmapImage; +import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +public final class CraftEngineImages { + + private CraftEngineImages() {} + + /** + * Returns an unmodifiable map of all currently loaded custom images. + * The map keys represent unique identifiers, and the values are the corresponding BitmapImage instances. + * + *

Important: Do not attempt to access this method during the onEnable phase + * as it will be empty. Instead, listen for the {@code CraftEngineReloadEvent} and use this method + * after the event is fired to obtain the complete image list. + * + * @return a non-null map containing all loaded custom images + */ + @NotNull + public static Map loadedImages() { + return BukkitFontManager.instance().loadedImages(); + } + + /** + * Gets a custom image by ID + * + * @param id id + * @return the custom image + */ + @Nullable + public static BitmapImage byId(@NotNull Key id) { + return BukkitFontManager.instance().loadedImages().get(id); + } +} 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 36c421336..abcf5d08f 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 @@ -44,7 +44,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { // 事件监听器 private final BlockEventListener blockEventListener; // 用于缓存string形式的方块状态到原版方块状态 - private final Map blockStateCache = new HashMap<>(1024); + private final Map blockStateCache = new HashMap<>(1024); // 用于临时存储可燃烧自定义方块的列表 private final List burnableBlocks = new ArrayList<>(); // 可燃烧的方块 @@ -169,25 +169,22 @@ public final class BukkitBlockManager extends AbstractBlockManager { @Override public BlockStateWrapper createVanillaBlockState(String blockState) { - Object state = parseBlockState(blockState); - if (state == null) return null; - return BlockStateUtils.toBlockStateWrapper(state); + return this.blockStateCache.computeIfAbsent(blockState, k -> { + Object state = parseBlockState(k); + if (state == null) return null; + return BlockStateUtils.toBlockStateWrapper(state); + }); } @Nullable private Object parseBlockState(String state) { - if (this.blockStateCache.containsKey(state)) { - return this.blockStateCache.get(state); - } try { Object registryOrLookUp = MBuiltInRegistries.BLOCK; if (CoreReflections.method$Registry$asLookup != null) { registryOrLookUp = CoreReflections.method$Registry$asLookup.invoke(registryOrLookUp); } Object result = CoreReflections.method$BlockStateParser$parseForBlock.invoke(null, registryOrLookUp, state, false); - Object resultState = CoreReflections.method$BlockStateParser$BlockResult$blockState.invoke(result); - this.blockStateCache.put(state, resultState); - return resultState; + return CoreReflections.method$BlockStateParser$BlockResult$blockState.invoke(result); } catch (Exception e) { Debugger.BLOCK.warn(() -> "Failed to create block state: " + state, e); return null; 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 f6304a758..637fb20a5 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 @@ -36,11 +36,17 @@ import java.lang.reflect.InvocationTargetException; import java.util.*; public class BukkitFontManager extends AbstractFontManager implements Listener { + private static BukkitFontManager instance; private final BukkitCraftEngine plugin; public BukkitFontManager(BukkitCraftEngine plugin) { super(plugin); this.plugin = plugin; + instance = this; + } + + public static BukkitFontManager instance() { + return instance; } @Override 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 e5a984612..fe991ca7f 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 @@ -348,6 +348,11 @@ public class BukkitCraftEngine extends CraftEngine { return (BukkitPackManager) packManager; } + @Override + public BukkitFontManager fontManager() { + return (BukkitFontManager) fontManager; + } + @SuppressWarnings("ResultOfMethodCallIgnored") @Override public void saveResource(String resourcePath) { 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 024b38db9..14c4d9378 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 @@ -56,7 +56,8 @@ public class BukkitCommandManager extends AbstractCommandManager new ListResourceCommand(this, plugin), new UploadPackCommand(this, plugin), new SendResourcePackCommand(this, plugin), - new DebugSaveDefaultResourcesCommand(this, plugin) + new DebugSaveDefaultResourcesCommand(this, plugin), + new DebugCleanCacheCommand(this, plugin) )); final LegacyPaperCommandManager manager = (LegacyPaperCommandManager) getCommandManager(); manager.settings().set(ManagerSetting.ALLOW_UNSAFE_REGISTRATION, true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java new file mode 100644 index 000000000..8337140f6 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java @@ -0,0 +1,84 @@ +package net.momirealms.craftengine.bukkit.plugin.command.feature; + +import net.momirealms.craftengine.bukkit.api.CraftEngineItems; +import net.momirealms.craftengine.bukkit.font.BukkitFontManager; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.core.pack.allocator.IdAllocator; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.command.CommandSender; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.incendo.cloud.Command; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.StringParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +public class DebugCleanCacheCommand extends BukkitCommandFeature { + + public DebugCleanCacheCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { + super(commandManager, plugin); + } + + @Override + public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { + return builder + .required("type", StringParser.stringComponent().suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(List.of(Suggestion.suggestion("custom-model-data"), Suggestion.suggestion("custom-block-states"), Suggestion.suggestion("visual-block-states"), Suggestion.suggestion("font"))); + } + })) + .handler(context -> { + if (this.plugin().isReloading()) { + context.sender().sendMessage("The plugin is reloading. Please wait until the process is complete."); + return; + } + String type = context.get("type"); + switch (type) { + case "custom-model-data" -> { + BukkitItemManager instance = BukkitItemManager.instance(); + Set ids = CraftEngineItems.loadedItems().keySet().stream().map(Key::toString).collect(Collectors.toSet()); + int total = 0; + for (Map.Entry entry : instance.itemParser().idAllocators().entrySet()) { + List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); + total += removed.size(); + try { + entry.getValue().saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving custom model data allocation for material " + entry.getKey().asString(), e); + return; + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unused item: " + id); + } + } + context.sender().sendMessage("Cleaned " + total + " unused custom model data"); + } + case "custom-block-states" -> { + } + case "visual-block-states" -> { + } + case "font", "images" -> { + BukkitFontManager instance = this.plugin().fontManager(); + + } + } + }); + } + + @Override + public String getFeatureID() { + return "debug_clean_cache"; + } +} diff --git a/common-files/src/main/resources/commands.yml b/common-files/src/main/resources/commands.yml index 3a2b6c8de..9ba12ceeb 100644 --- a/common-files/src/main/resources/commands.yml +++ b/common-files/src/main/resources/commands.yml @@ -210,6 +210,13 @@ debug_save_default_resources: - /craftengine debug save-default-resources - /ce debug save-default-resources +debug_clean_cache: + enable: true + permission: ce.command.debug.clean_cache + usage: + - /craftengine debug clean-cache + - /ce debug clean-cache + debug_test: enable: true permission: ce.command.debug.test diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml index 07e6a3f1e..7e36d6d45 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/chessboard_block.yml @@ -34,7 +34,7 @@ items: default: north appearances: east: - state: note_block:18 + auto-state: solid model: path: minecraft:block/custom/chessboard_block y: 270 @@ -43,16 +43,16 @@ items: textures: pattern: minecraft:block/custom/chessboard_block north: - state: note_block:19 + auto-state: solid model: path: minecraft:block/custom/chessboard_block y: 180 south: - state: note_block:20 + auto-state: solid model: path: minecraft:block/custom/chessboard_block west: - state: note_block:21 + auto-state: solid model: path: minecraft:block/custom/chessboard_block y: 90 diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml b/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml index 4776b2d4d..420809bc8 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/chinese_lantern.yml @@ -25,7 +25,7 @@ items: luminance: 15 map-color: 36 state: - state: note_block:15 + auto-state: solid model: path: minecraft:block/custom/chinese_lantern generation: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml b/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml index 94185e5aa..9d9b8bf83 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/copper_coil.yml @@ -36,7 +36,7 @@ items: default: false appearances: off: - state: cactus:0 + auto-state: cactus model: path: minecraft:block/custom/copper_coil generation: @@ -47,7 +47,7 @@ items: top: minecraft:block/custom/copper_coil side: minecraft:block/custom/copper_coil_side on: - state: cactus:1 + auto-state: cactus model: path: minecraft:block/custom/copper_coil_on generation: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml b/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml index ccb1fad33..0b61f7161 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/ender_pearl_flower.yml @@ -90,7 +90,7 @@ blocks: range: 0~2 appearances: stage_0: - state: tripwire:1 + auto-state: lower_tripwire models: - path: minecraft:block/custom/ender_pearl_flower_stage_0 generation: @@ -98,7 +98,7 @@ blocks: textures: cross: minecraft:block/custom/ender_pearl_flower_stage_0 stage_1: - state: tripwire:0 + auto-state: higher_tripwire models: - path: minecraft:block/custom/ender_pearl_flower_stage_1 generation: @@ -106,7 +106,7 @@ blocks: textures: cross: minecraft:block/custom/ender_pearl_flower_stage_1 stage_2: - state: sugar_cane:3 + auto-state: sugar_cane models: - path: minecraft:block/custom/ender_pearl_flower_stage_2 generation: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml b/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml index 5e2b00ba4..52a2815fd 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/fairy_flower.yml @@ -26,7 +26,7 @@ items: loot: template: default:loot_table/self state: - state: sugar_cane:0 + auto-state: sugar_cane models: - path: minecraft:block/custom/fairy_flower_1 weight: 100 diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml b/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml index f24859eef..4213b62bd 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/flame_cane.yml @@ -53,7 +53,7 @@ items: range: 0~5 appearances: default: - state: sugar_cane:2 + auto-state: sugar_cane models: - path: minecraft:block/custom/flame_cane_1 weight: 1 diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml index 17ccff09d..e114b183c 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/gunpowder_block.yml @@ -27,7 +27,7 @@ items: instrument: snare map-color: 45 state: - state: note_block:16 + auto-state: solid model: path: minecraft:block/custom/gunpowder_block generation: @@ -59,7 +59,7 @@ items: instrument: basedrum map-color: 45 state: - state: note_block:17 + auto-state: solid model: path: minecraft:block/custom/solid_gunpowder_block generation: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 61ccd87bc..6002d41ac 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -27,7 +27,6 @@ items: states: template: default:block_state/pillar arguments: - base_block: note_block texture_top_path: minecraft:block/custom/palm_log_top texture_side_path: minecraft:block/custom/palm_log model_vertical_path: minecraft:block/custom/palm_log @@ -57,7 +56,6 @@ items: states: template: default:block_state/pillar arguments: - base_block: note_block texture_top_path: minecraft:block/custom/stripped_palm_log_top texture_side_path: minecraft:block/custom/stripped_palm_log model_vertical_path: minecraft:block/custom/stripped_palm_log @@ -90,7 +88,6 @@ items: states: template: default:block_state/pillar arguments: - base_block: note_block texture_top_path: minecraft:block/custom/palm_log texture_side_path: minecraft:block/custom/palm_log model_vertical_path: minecraft:block/custom/palm_wood @@ -120,7 +117,6 @@ items: states: template: default:block_state/pillar arguments: - base_block: note_block texture_top_path: minecraft:block/custom/stripped_palm_log texture_side_path: minecraft:block/custom/stripped_palm_log model_vertical_path: minecraft:block/custom/stripped_palm_wood @@ -151,7 +147,7 @@ items: template: default:model/simplified_cube_all arguments: path: minecraft:block/custom/palm_planks - state: note_block:12 + auto-state: solid default:palm_sapling: material: nether_brick settings: @@ -187,7 +183,7 @@ items: range: 0~1 appearances: default: - state: oak_sapling:0 + auto-state: sapling model: path: minecraft:block/custom/palm_sapling generation: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml b/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml index 5a164c44e..23fe24d71 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/pebble.yml @@ -58,7 +58,7 @@ items: default: 1 appearances: one: - state: tripwire:2 + auto-state: lower_tripwire models: - path: minecraft:block/custom/pebble_1 weight: 1 @@ -72,7 +72,7 @@ items: weight: 1 y: 270 two: - state: tripwire:3 + auto-state: lower_tripwire models: - path: minecraft:block/custom/pebble_2 weight: 1 @@ -86,7 +86,7 @@ items: weight: 1 y: 270 three: - state: tripwire:4 + auto-state: higher_tripwire models: - path: minecraft:block/custom/pebble_3 weight: 1 diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml b/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml index c43425c81..de1e00be9 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/reed.yml @@ -25,7 +25,7 @@ items: loot: template: default:loot_table/self state: - state: sugar_cane:1 + auto-state: sugar_cane model: path: minecraft:block/custom/reed recipes: diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml b/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml index 710804ef9..63b13e353 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/safe_block.yml @@ -48,7 +48,7 @@ items: default: false appearances: east: - state: note_block:22 + auto-state: note_block model: path: minecraft:block/custom/safe_block y: 90 @@ -59,7 +59,7 @@ items: side: minecraft:block/custom/safe_block_side top: minecraft:block/custom/safe_block_top east_open: - state: note_block:23 + auto-state: note_block model: path: minecraft:block/custom/safe_block_open y: 90 @@ -70,30 +70,30 @@ items: side: minecraft:block/custom/safe_block_side top: minecraft:block/custom/safe_block_top north: - state: note_block:24 + auto-state: note_block model: path: minecraft:block/custom/safe_block north_open: - state: note_block:25 + auto-state: note_block model: path: minecraft:block/custom/safe_block_open south: - state: note_block:26 + auto-state: note_block model: path: minecraft:block/custom/safe_block y: 180 south_open: - state: note_block:27 + auto-state: note_block model: path: minecraft:block/custom/safe_block_open y: 180 west: - state: note_block:28 + auto-state: note_block model: path: minecraft:block/custom/safe_block y: 270 west_open: - state: note_block:29 + auto-state: note_block model: path: minecraft:block/custom/safe_block_open y: 270 diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml b/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml index 0eee914e4..6721d3027 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml @@ -50,7 +50,7 @@ blocks: arguments: break_power: 2 state: - state: note_block:13 + auto-state: solid model: template: default:model/simplified_cube_all arguments: 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 5912b31f5..da609c8b0 100644 --- a/common-files/src/main/resources/resources/default/configuration/templates.yml +++ b/common-files/src/main/resources/resources/default/configuration/templates.yml @@ -862,7 +862,7 @@ templates#block_states: default: y appearances: axisY: - state: ${base_block} + auto-state: solid model: path: ${model_vertical_path} generation: @@ -871,7 +871,7 @@ templates#block_states: end: ${texture_top_path} side: ${texture_side_path} axisX: - state: ${base_block} + auto-state: solid model: x: 90 y: 90 @@ -882,7 +882,7 @@ templates#block_states: end: ${texture_top_path} side: ${texture_side_path} axisZ: - state: ${base_block} + auto-state: solid model: x: 90 path: ${model_horizontal_path} @@ -913,7 +913,7 @@ templates#block_states: range: 1~7 appearances: default: - state: ${default_state} + auto-state: leaves model: path: ${model_path} generation: @@ -921,7 +921,7 @@ templates#block_states: textures: all: ${texture_path} waterlogged: - state: ${waterlogged_state} + auto-state: waterlogged_leaves model: path: ${model_path} variants: @@ -2231,6 +2231,11 @@ templates#block_states: x: 180 y: 180 variants: + waterlogged=true: + settings: + resistance: 1200.0 + burnable: false + fluid-state: water facing=east,half=bottom,shape=inner_left,waterlogged=false: appearance: facing=east,half=bottom,shape=inner_left,waterlogged=false facing=east,half=bottom,shape=inner_right,waterlogged=false: @@ -2313,244 +2318,85 @@ templates#block_states: appearance: facing=west,half=top,shape=straight,waterlogged=false facing=east,half=bottom,shape=inner_left,waterlogged=true: appearance: facing=east,half=bottom,shape=inner_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=east,half=bottom,shape=inner_right,waterlogged=true: appearance: facing=east,half=bottom,shape=inner_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=east,half=bottom,shape=outer_left,waterlogged=true: appearance: facing=east,half=bottom,shape=outer_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=east,half=bottom,shape=outer_right,waterlogged=true: appearance: facing=east,half=bottom,shape=outer_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=east,half=bottom,shape=straight,waterlogged=true: appearance: facing=east,half=bottom,shape=straight,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=east,half=top,shape=inner_left,waterlogged=true: appearance: facing=east,half=top,shape=inner_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=east,half=top,shape=inner_right,waterlogged=true: appearance: facing=east,half=top,shape=inner_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=east,half=top,shape=outer_left,waterlogged=true: appearance: facing=east,half=top,shape=outer_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=east,half=top,shape=outer_right,waterlogged=true: appearance: facing=east,half=top,shape=outer_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=east,half=top,shape=straight,waterlogged=true: appearance: facing=east,half=top,shape=straight,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=bottom,shape=inner_left,waterlogged=true: appearance: facing=north,half=bottom,shape=inner_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=bottom,shape=inner_right,waterlogged=true: appearance: facing=north,half=bottom,shape=inner_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=bottom,shape=outer_left,waterlogged=true: appearance: facing=north,half=bottom,shape=outer_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=bottom,shape=outer_right,waterlogged=true: appearance: facing=north,half=bottom,shape=outer_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=bottom,shape=straight,waterlogged=true: appearance: facing=north,half=bottom,shape=straight,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=top,shape=inner_left,waterlogged=true: appearance: facing=north,half=top,shape=inner_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=top,shape=inner_right,waterlogged=true: appearance: facing=north,half=top,shape=inner_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=top,shape=outer_left,waterlogged=true: appearance: facing=north,half=top,shape=outer_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=top,shape=outer_right,waterlogged=true: appearance: facing=north,half=top,shape=outer_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=north,half=top,shape=straight,waterlogged=true: appearance: facing=north,half=top,shape=straight,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=bottom,shape=inner_left,waterlogged=true: appearance: facing=south,half=bottom,shape=inner_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=bottom,shape=inner_right,waterlogged=true: appearance: facing=south,half=bottom,shape=inner_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=bottom,shape=outer_left,waterlogged=true: appearance: facing=south,half=bottom,shape=outer_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=bottom,shape=outer_right,waterlogged=true: appearance: facing=south,half=bottom,shape=outer_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=bottom,shape=straight,waterlogged=true: appearance: facing=south,half=bottom,shape=straight,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=top,shape=inner_left,waterlogged=true: appearance: facing=south,half=top,shape=inner_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=top,shape=inner_right,waterlogged=true: appearance: facing=south,half=top,shape=inner_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=top,shape=outer_left,waterlogged=true: appearance: facing=south,half=top,shape=outer_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=top,shape=outer_right,waterlogged=true: appearance: facing=south,half=top,shape=outer_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=south,half=top,shape=straight,waterlogged=true: appearance: facing=south,half=top,shape=straight,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=bottom,shape=inner_left,waterlogged=true: appearance: facing=west,half=bottom,shape=inner_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=bottom,shape=inner_right,waterlogged=true: appearance: facing=west,half=bottom,shape=inner_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=bottom,shape=outer_left,waterlogged=true: appearance: facing=west,half=bottom,shape=outer_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=bottom,shape=outer_right,waterlogged=true: appearance: facing=west,half=bottom,shape=outer_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=bottom,shape=straight,waterlogged=true: appearance: facing=west,half=bottom,shape=straight,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=top,shape=inner_left,waterlogged=true: appearance: facing=west,half=top,shape=inner_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=top,shape=inner_right,waterlogged=true: appearance: facing=west,half=top,shape=inner_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=top,shape=outer_left,waterlogged=true: appearance: facing=west,half=top,shape=outer_left,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=top,shape=outer_right,waterlogged=true: appearance: facing=west,half=top,shape=outer_right,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water facing=west,half=top,shape=straight,waterlogged=true: appearance: facing=west,half=top,shape=straight,waterlogged=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water + # pressure plate block default:block_state/pressure_plate: properties: @@ -3171,6 +3017,11 @@ templates#block_states: - item: ${fence_side_item} rotation: 270 variants: + waterlogged=true: + settings: + resistance: 1200.0 + burnable: false + fluid-state: water east=false,north=false,south=false,waterlogged=false,west=false: appearance: east=false,north=false,south=false,waterlogged=false,west=false east=true,north=false,south=false,waterlogged=false,west=false: @@ -3205,100 +3056,37 @@ templates#block_states: appearance: east=true,north=true,south=true,waterlogged=false,west=true east=false,north=false,south=false,waterlogged=true,west=false: appearance: east=false,north=false,south=false,waterlogged=true,west=false - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=true,north=false,south=false,waterlogged=true,west=false: appearance: east=true,north=false,south=false,waterlogged=true,west=false - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=false,north=true,south=false,waterlogged=true,west=false: appearance: east=false,north=true,south=false,waterlogged=true,west=false - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=false,north=false,south=true,waterlogged=true,west=false: appearance: east=false,north=false,south=true,waterlogged=true,west=false - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=false,north=false,south=false,waterlogged=true,west=true: appearance: east=false,north=false,south=false,waterlogged=true,west=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=true,north=true,south=false,waterlogged=true,west=false: appearance: east=true,north=true,south=false,waterlogged=true,west=false - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=true,north=false,south=true,waterlogged=true,west=false: appearance: east=true,north=false,south=true,waterlogged=true,west=false - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=true,north=false,south=false,waterlogged=true,west=true: appearance: east=true,north=false,south=false,waterlogged=true,west=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=false,north=true,south=true,waterlogged=true,west=false: appearance: east=false,north=true,south=true,waterlogged=true,west=false - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=false,north=true,south=false,waterlogged=true,west=true: appearance: east=false,north=true,south=false,waterlogged=true,west=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=false,north=false,south=true,waterlogged=true,west=true: appearance: east=false,north=false,south=true,waterlogged=true,west=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=true,north=true,south=true,waterlogged=true,west=false: appearance: east=true,north=true,south=true,waterlogged=true,west=false - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=true,north=true,south=false,waterlogged=true,west=true: appearance: east=true,north=true,south=false,waterlogged=true,west=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=true,north=false,south=true,waterlogged=true,west=true: appearance: east=true,north=false,south=true,waterlogged=true,west=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=false,north=true,south=true,waterlogged=true,west=true: appearance: east=false,north=true,south=true,waterlogged=true,west=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water east=true,north=true,south=true,waterlogged=true,west=true: appearance: east=true,north=true,south=true,waterlogged=true,west=true - settings: - resistance: 1200.0 - burnable: false - fluid-state: water + # recipes templates#recipes: default:recipe/planks: diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 5679ea63c..acd02e1a4 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -277,6 +277,8 @@ warning.config.block.state.entity_renderer.better_model.missing_model: " warning.config.block.state.entity_renderer.model_engine.missing_model: "Issue found in file - The block '' is missing the required 'model' argument for 'model_engine' entity renderer." warning.config.block.state.variant.invalid_appearance: "Issue found in file - The block '' has an error that the variant '' is using a non-existing appearance ''." warning.config.block.state.invalid_vanilla: "Issue found in file - The block '' is using an invalid vanilla block state ''." +warning.config.block.state.invalid_auto_state: "Issue found in file - The block '' is using an invalid auto-state ''. Allowed values: []." +warning.config.block.state.auto_state.exhausted: "Issue found in file - Cannot allocate visual block state for block '' as the slots('') in group '' have been exhausted." warning.config.block.state.unavailable_vanilla: "Issue found in file - The block '' is using an unavailable vanilla block state ''. Please free that state in block-state-mappings." warning.config.block.state.invalid_vanilla_id: "Issue found in file - The block '' is using a vanilla block state '' that exceeds the available slot range '0~'." warning.config.block.state.invalid_id: "Issue found in file - The block state ID range () used by block '' is outside the valid range of 0 to . Please add more server-side blocks in 'config.yml' if the current slots are exhausted." diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 5d5b66231..8f0af28ff 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -18,9 +18,9 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.pack.PendingConfigSection; import net.momirealms.craftengine.core.pack.ResourceLocation; -import net.momirealms.craftengine.core.pack.allocator.BlockStateAllocator; import net.momirealms.craftengine.core.pack.allocator.BlockStateCandidate; import net.momirealms.craftengine.core.pack.allocator.IdAllocator; +import net.momirealms.craftengine.core.pack.allocator.VisualBlockStateAllocator; import net.momirealms.craftengine.core.pack.model.generation.AbstractModelGenerator; import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -60,8 +60,6 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected final List cachedSuggestions = new ArrayList<>(); // 缓存的使用中的命名空间 protected final Set namespacesInUse = new HashSet<>(); - // 用于检测单个外观方块状态是否被绑定了不同模型 - protected final Map tempVanillaBlockStateModels = new Int2ObjectOpenHashMap<>(); // Map<方块类型, Map<方块状态NBT,模型>>,用于生成block state json protected final Map> blockStateOverrides = new HashMap<>(); // 用于生成mod使用的block state json @@ -81,7 +79,9 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 自定义状态列表,会随着重载变化 protected final ImmutableBlockState[] immutableBlockStates; // 倒推缓存 - protected final BlockStateCandidate[] reversedBlockStateArranger; + protected final BlockStateCandidate[] autoVisualBlockStateCandidates; + // 用于检测单个外观方块状态是否被绑定了不同模型 + protected final JsonElement[] tempVanillaBlockStateModels; // 临时存储哪些视觉方块被使用了 protected final Set tempVisualBlockStatesInUse = new HashSet<>(); protected final Set tempVisualBlocksInUse = new HashSet<>(); @@ -91,14 +91,15 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem protected AbstractBlockManager(CraftEngine plugin, int vanillaBlockStateCount, int customBlockCount) { super(plugin); this.vanillaBlockStateCount = vanillaBlockStateCount; - this.blockParser = new BlockParser(); - this.blockStateMappingParser = new BlockStateMappingParser(); this.customBlocks = new DelegatingBlock[customBlockCount]; this.customBlockHolders = new Object[customBlockCount]; this.customBlockStates = new DelegatingBlockState[customBlockCount]; this.immutableBlockStates = new ImmutableBlockState[customBlockCount]; this.blockStateMappings = new int[customBlockCount + vanillaBlockStateCount]; - this.reversedBlockStateArranger = new BlockStateCandidate[vanillaBlockStateCount]; + this.autoVisualBlockStateCandidates = new BlockStateCandidate[vanillaBlockStateCount]; + this.tempVanillaBlockStateModels = new JsonElement[vanillaBlockStateCount]; + this.blockParser = new BlockParser(this.autoVisualBlockStateCandidates); + this.blockStateMappingParser = new BlockStateMappingParser(); Arrays.fill(this.blockStateMappings, -1); } @@ -130,7 +131,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.appearanceToRealState.clear(); Arrays.fill(this.blockStateMappings, -1); Arrays.fill(this.immutableBlockStates, EmptyBlock.STATE); - Arrays.fill(this.reversedBlockStateArranger, null); + Arrays.fill(this.autoVisualBlockStateCandidates, null); + for (AutoStateGroup autoStateGroup : AutoStateGroup.values()) { + autoStateGroup.reset(); + } } @Override @@ -188,7 +192,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } protected void clearCache() { - this.tempVanillaBlockStateModels.clear(); + Arrays.fill(this.tempVanillaBlockStateModels, null); this.tempVisualBlockStatesInUse.clear(); this.tempVisualBlocksInUse.clear(); } @@ -275,26 +279,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem Key blockOwnerId = getBlockOwnerId(beforeState); List blockStateWrappers = AbstractBlockManager.this.blockStateArranger.computeIfAbsent(blockOwnerId, k -> new ArrayList<>()); blockStateWrappers.add(beforeState); - AbstractBlockManager.this.reversedBlockStateArranger[beforeState.registryId()] = blockParser.createVisualBlockCandidate(beforeState); - + AbstractBlockManager.this.autoVisualBlockStateCandidates[beforeState.registryId()] = createVisualBlockCandidate(beforeState); } exceptionCollector.throwIfPresent(); } - } - - public class BlockParser extends IdSectionConfigParser { - public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; - private final IdAllocator internalIdAllocator; - private final List pendingConfigSections = new ArrayList<>(); - private final BlockStateAllocator[] visualBlockStateAllocators = new BlockStateAllocator[AutoStateGroup.values().length]; - - public BlockParser() { - this.internalIdAllocator = new IdAllocator(AbstractBlockManager.this.plugin.dataFolderPath().resolve("cache").resolve("custom-block-states.json")); - } - - public void addPendingConfigSection(PendingConfigSection section) { - this.pendingConfigSections.add(section); - } @Nullable public BlockStateCandidate createVisualBlockCandidate(BlockStateWrapper blockState) { @@ -302,40 +290,58 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem if (!groups.isEmpty()) { BlockStateCandidate candidate = new BlockStateCandidate(blockState); for (AutoStateGroup group : groups) { - getOrCreateBlockStateAllocator(group).addCandidate(candidate); + group.addCandidate(candidate); } return candidate; } return null; } + } - private BlockStateAllocator getOrCreateBlockStateAllocator(AutoStateGroup group) { - int index = group.ordinal(); - BlockStateAllocator visualBlockStateAllocator = this.visualBlockStateAllocators[index]; - if (visualBlockStateAllocator == null) { - visualBlockStateAllocator = new BlockStateAllocator(); - this.visualBlockStateAllocators[index] = visualBlockStateAllocator; - } - return visualBlockStateAllocator; + public class BlockParser extends IdSectionConfigParser { + public static final String[] CONFIG_SECTION_NAME = new String[]{"blocks", "block"}; + private final IdAllocator internalIdAllocator; + private final VisualBlockStateAllocator visualBlockStateAllocator; + private final List pendingConfigSections = new ArrayList<>(); + + public BlockParser(BlockStateCandidate[] candidates) { + this.internalIdAllocator = new IdAllocator(AbstractBlockManager.this.plugin.dataFolderPath().resolve("cache").resolve("custom-block-states.json")); + this.visualBlockStateAllocator = new VisualBlockStateAllocator(AbstractBlockManager.this.plugin.dataFolderPath().resolve("cache").resolve("visual-block-states.json"), candidates, AbstractBlockManager.this::createVanillaBlockState); + } + + public void addPendingConfigSection(PendingConfigSection section) { + this.pendingConfigSections.add(section); } @Override public void postProcess() { + this.visualBlockStateAllocator.processPendingAllocations(); + try { + this.visualBlockStateAllocator.saveToCache(); + } catch (IOException e) { + AbstractBlockManager.this.plugin.logger().warn("Error while saving visual block states allocation", e); + } this.internalIdAllocator.processPendingAllocations(); try { this.internalIdAllocator.saveToCache(); } catch (IOException e) { - AbstractBlockManager.this.plugin.logger().warn("Error while saving custom block state allocation", e); + AbstractBlockManager.this.plugin.logger().warn("Error while saving custom block states allocation", e); } } @Override public void preProcess() { + this.visualBlockStateAllocator.reset(); + try { + this.visualBlockStateAllocator.loadFromCache(); + } catch (IOException e) { + AbstractBlockManager.this.plugin.logger().warn("Error while loading visual block states allocation cache", e); + } this.internalIdAllocator.reset(0, Config.serverSideBlocks() - 1); try { this.internalIdAllocator.loadFromCache(); } catch (IOException e) { - AbstractBlockManager.this.plugin.logger().warn("Error while loading custom block state allocation cache", e); + AbstractBlockManager.this.plugin.logger().warn("Error while loading custom block states allocation cache", e); } for (PendingConfigSection section : this.pendingConfigSections) { ResourceConfigUtils.runCatching( @@ -437,9 +443,9 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } - CompletableFutures.allOf(internalIdAllocators).whenComplete((v, t) -> ResourceConfigUtils.runCatching(path, node, () -> { - if (t != null) { - if (t instanceof CompletionException e) { + CompletableFutures.allOf(internalIdAllocators).whenComplete((v1, t1) -> ResourceConfigUtils.runCatching(path, node, () -> { + if (t1 != null) { + if (t1 instanceof CompletionException e) { Throwable cause = e.getCause(); // 这里不会有conflict了,因为之前已经判断过了 if (cause instanceof IdAllocator.IdExhaustedException) { @@ -449,7 +455,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return; } } - throw new RuntimeException("Unknown error occurred", t); + throw new RuntimeException("Unknown error occurred", t1); } for (int i = 0; i < internalIdAllocators.size(); i++) { @@ -472,110 +478,164 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem ); BlockBehavior blockBehavior = createBlockBehavior(customBlock, MiscUtils.getAsMapList(ResourceConfigUtils.get(section, "behavior", "behaviors"))); - // 单状态 + Map> appearanceConfigs; + Map> futureVisualStates = new HashMap<>(); if (singleState) { - BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(stateSection.get("state"), "warning.config.block.state.missing_state")); - this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(stateSection, "model", "models")); - ImmutableBlockState onlyState = states.getFirst(); - // 为唯一的状态绑定外观 - onlyState.setVanillaBlockState(appearanceState); - parseBlockEntityRender(stateSection.get("entity-renderer")).ifPresent(onlyState::setConstantRenderers); + appearanceConfigs = Map.of("", stateSection); } else { - BlockStateWrapper anyAppearanceState = null; - Map appearancesSection = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances"); - // 也不能为空 - if (appearancesSection.isEmpty()) { - throw new LocalizedResourceConfigException("warning.config.block.state.missing_appearances"); - } - Map appearances = Maps.newHashMap(); - // 先解析所有的外观 - for (Map.Entry entry : appearancesSection.entrySet()) { - Map appearanceSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); - // 解析对应的视觉方块 - BlockStateWrapper appearanceState = parsePluginFormattedBlockState(ResourceConfigUtils.requireNonEmptyStringOrThrow(appearanceSection.get("state"), "warning.config.block.state.missing_state")); - this.arrangeModelForStateAndVerify(appearanceState, ResourceConfigUtils.get(appearanceSection, "model", "models")); - appearances.put(entry.getKey(), new BlockStateAppearance(appearanceState, parseBlockEntityRender(appearanceSection.get("entity-renderer")))); - if (anyAppearanceState == null) { - anyAppearanceState = appearanceState; - } - } - // 解析变体 - Map variantsSection = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("variants"), "warning.config.block.state.missing_variants"), "variants"); - for (Map.Entry entry : variantsSection.entrySet()) { - Map variantSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); - String variantNBT = entry.getKey(); - // 先解析nbt,找到需要修改的方块状态 - CompoundTag tag = BlockNbtParser.deserialize(variantProvider, variantNBT); - if (tag == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", variantNBT); - } - List possibleStates = variantProvider.getPossibleStates(tag); - Map anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings"); - if (anotherSetting != null) { - for (ImmutableBlockState possibleState : possibleStates) { - possibleState.setSettings(BlockSettings.ofFullCopy(possibleState.settings(), anotherSetting)); - } - } - String appearanceName = ResourceConfigUtils.getAsString(variantSection.get("appearance")); - if (appearanceName != null) { - BlockStateAppearance appearance = appearances.get(appearanceName); - if (appearance == null) { - throw new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearanceName); - } - for (ImmutableBlockState possibleState : possibleStates) { - possibleState.setVanillaBlockState(appearance.blockState()); - appearance.blockEntityRenderer().ifPresent(possibleState::setConstantRenderers); - } - } - } - // 为没有外观的方块状态填充 - for (ImmutableBlockState blockState : states) { - if (blockState.vanillaBlockState() == null) { - blockState.setVanillaBlockState(anyAppearanceState); - } + Map rawAppearancesSection = ResourceConfigUtils.getAsMap(ResourceConfigUtils.requireNonNullOrThrow(stateSection.get("appearances"), "warning.config.block.state.missing_appearances"), "appearances"); + appearanceConfigs = new LinkedHashMap<>(4); + for (Map.Entry entry : rawAppearancesSection.entrySet()) { + appearanceConfigs.put(entry.getKey(), ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey())); } } - // 获取方块实体行为 - EntityBlockBehavior entityBlockBehavior = blockBehavior.getEntityBehavior(); - boolean isEntityBlock = entityBlockBehavior != null; - - // 绑定行为 - for (ImmutableBlockState state : states) { - if (isEntityBlock) { - state.setBlockEntityType(entityBlockBehavior.blockEntityType()); - } - state.setBehavior(blockBehavior); - int internalId = state.customBlockState().registryId(); - BlockStateWrapper visualState = state.vanillaBlockState(); - int appearanceId = visualState.registryId(); - int index = internalId - AbstractBlockManager.this.vanillaBlockStateCount; - AbstractBlockManager.this.immutableBlockStates[index] = state; - AbstractBlockManager.this.blockStateMappings[internalId] = appearanceId; - AbstractBlockManager.this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId); - AbstractBlockManager.this.tempVisualBlockStatesInUse.add(visualState); - AbstractBlockManager.this.tempVisualBlocksInUse.add(getBlockOwnerId(visualState)); - AbstractBlockManager.this.applyPlatformSettings(state); - // generate mod assets - if (Config.generateModAssets()) { - AbstractBlockManager.this.modBlockStateOverrides.put(BlockManager.createCustomBlockKey(index), Optional.ofNullable(AbstractBlockManager.this.tempVanillaBlockStateModels.get(appearanceId)) - .orElseGet(() -> { - // 如果未指定模型,说明复用原版模型?但是部分模型是多部位模型,无法使用变体解决问题 - // 未来需要靠mod重构彻底解决问题 - JsonObject json = new JsonObject(); - json.addProperty("model", "minecraft:block/air"); - return json; - })); + for (Map.Entry> entry : appearanceConfigs.entrySet()) { + Map appearanceSection = entry.getValue(); + if (appearanceSection.containsKey("state")) { + String appearanceName = entry.getKey(); + futureVisualStates.put( + appearanceName, + this.visualBlockStateAllocator.assignFixedBlockState(appearanceName.isEmpty() ? id.asString() : id.asString() + ":" + appearanceName, parsePluginFormattedBlockState(appearanceSection.get("state").toString())) + ); + } else if (stateSection.containsKey("auto-state")) { + String autoStateId = stateSection.get("auto-state").toString(); + AutoStateGroup group = AutoStateGroup.byId(autoStateId); + if (group == null) { + throw new LocalizedResourceConfigException("warning.config.block.state.invalid_auto_state", autoStateId, EnumUtils.toString(AutoStateGroup.values())); + } + String appearanceName = entry.getKey(); + futureVisualStates.put( + appearanceName, + this.visualBlockStateAllocator.requestAutoState(appearanceName.isEmpty() ? id.asString() : id.asString() + ":" + appearanceName, group) + ); + } else { + throw new LocalizedResourceConfigException("warning.config.block.state.missing_state"); } } - // 一定要到最后再绑定 - customBlock.setBehavior(blockBehavior); - holder.bindValue(customBlock); + CompletableFutures.allOf(futureVisualStates.values()).whenComplete((v2, t2) -> { + if (t2 != null) { + if (t2 instanceof CompletionException e) { + Throwable cause = e.getCause(); + if (cause instanceof VisualBlockStateAllocator.StateExhaustedException exhausted) { + throw new LocalizedResourceConfigException("warning.config.block.state.auto_state.exhausted", exhausted.group().id(), String.valueOf(exhausted.group().candidateCount())); + } else { + Debugger.BLOCK.warn(() -> "Unknown error while allocating visual block state.", cause); + return; + } + } + throw new RuntimeException("Unknown error occurred", t2); + } - // 添加方块 - AbstractBlockManager.this.byId.put(customBlock.id(), customBlock); + BlockStateAppearance anyAppearance = null; + Map appearances = new HashMap<>(); + for (Map.Entry> entry : appearanceConfigs.entrySet()) { + String appearanceName = entry.getKey(); + Map appearanceSection = entry.getValue(); + BlockStateWrapper visualBlockState; + try { + visualBlockState = futureVisualStates.get(appearanceName).get(); + } catch (InterruptedException | ExecutionException e) { + AbstractBlockManager.this.plugin.logger().warn("Interrupted while allocating visual block state for block " + id.asString(), e); + return; + } + this.arrangeModelForStateAndVerify(visualBlockState, ResourceConfigUtils.get(appearanceSection, "model", "models")); + BlockStateAppearance blockStateAppearance = new BlockStateAppearance(visualBlockState, parseBlockEntityRender(appearanceSection.get("entity-renderer"))); + appearances.put(appearanceName, blockStateAppearance); + if (anyAppearance == null) { + anyAppearance = blockStateAppearance; + } + } + // 至少有一个外观吧 + Objects.requireNonNull(anyAppearance, "any appearance should not be null"); + + ExceptionCollector exceptionCollector = new ExceptionCollector<>(); + if (!singleState) { + Map variantsSection = ResourceConfigUtils.getAsMapOrNull(stateSection.get("variants"), "variants"); + if (variantsSection != null) { + for (Map.Entry entry : variantsSection.entrySet()) { + Map variantSection = ResourceConfigUtils.getAsMap(entry.getValue(), entry.getKey()); + String variantNBT = entry.getKey(); + // 先解析nbt,找到需要修改的方块状态 + CompoundTag tag = BlockNbtParser.deserialize(variantProvider, variantNBT); + if (tag == null) { + exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.property.invalid_format", variantNBT)); + continue; + } + List possibleStates = variantProvider.getPossibleStates(tag); + Map anotherSetting = ResourceConfigUtils.getAsMapOrNull(variantSection.get("settings"), "settings"); + if (anotherSetting != null) { + for (ImmutableBlockState possibleState : possibleStates) { + possibleState.setSettings(BlockSettings.ofFullCopy(possibleState.settings(), anotherSetting)); + } + } + String appearanceName = ResourceConfigUtils.getAsString(variantSection.get("appearance")); + if (appearanceName != null) { + BlockStateAppearance appearance = appearances.get(appearanceName); + if (appearance == null) { + exceptionCollector.add(new LocalizedResourceConfigException("warning.config.block.state.variant.invalid_appearance", variantNBT, appearanceName)); + continue; + } + for (ImmutableBlockState possibleState : possibleStates) { + possibleState.setVanillaBlockState(appearance.blockState()); + appearance.blockEntityRenderer().ifPresent(possibleState::setConstantRenderers); + } + } + } + } + } + + // 获取方块实体行为 + EntityBlockBehavior entityBlockBehavior = blockBehavior.getEntityBehavior(); + boolean isEntityBlock = entityBlockBehavior != null; + + // 绑定行为 + for (ImmutableBlockState state : states) { + if (isEntityBlock) { + state.setBlockEntityType(entityBlockBehavior.blockEntityType()); + } + state.setBehavior(blockBehavior); + int internalId = state.customBlockState().registryId(); + BlockStateWrapper visualState = state.vanillaBlockState(); + // 校验,为未绑定外观的强行添加外观 + if (visualState == null) { + visualState = anyAppearance.blockState(); + state.setVanillaBlockState(visualState); + anyAppearance.blockEntityRenderer().ifPresent(state::setConstantRenderers); + } + int appearanceId = visualState.registryId(); + int index = internalId - AbstractBlockManager.this.vanillaBlockStateCount; + AbstractBlockManager.this.immutableBlockStates[index] = state; + AbstractBlockManager.this.blockStateMappings[internalId] = appearanceId; + AbstractBlockManager.this.appearanceToRealState.computeIfAbsent(appearanceId, k -> new IntArrayList()).add(internalId); + AbstractBlockManager.this.tempVisualBlockStatesInUse.add(visualState); + AbstractBlockManager.this.tempVisualBlocksInUse.add(getBlockOwnerId(visualState)); + AbstractBlockManager.this.applyPlatformSettings(state); + // generate mod assets + if (Config.generateModAssets()) { + AbstractBlockManager.this.modBlockStateOverrides.put(BlockManager.createCustomBlockKey(index), Optional.ofNullable(AbstractBlockManager.this.tempVanillaBlockStateModels[appearanceId]) + .orElseGet(() -> { + // 如果未指定模型,说明复用原版模型?但是部分模型是多部位模型,无法使用变体解决问题 + // 未来需要靠mod重构彻底解决问题 + JsonObject json = new JsonObject(); + json.addProperty("model", "minecraft:block/air"); + return json; + })); + } + } + + // 一定要到最后再绑定 + customBlock.setBehavior(blockBehavior); + holder.bindValue(customBlock); + + // 添加方块 + AbstractBlockManager.this.byId.put(customBlock.id(), customBlock); + + // 抛出次要警告 + exceptionCollector.throwIfPresent(); + }); }, () -> GsonHelper.get().toJson(section))); } @@ -622,12 +682,12 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 结合variants JsonElement combinedVariant = GsonHelper.combine(variants); Map overrideMap = AbstractBlockManager.this.blockStateOverrides.computeIfAbsent(blockId, k -> new HashMap<>()); - AbstractBlockManager.this.tempVanillaBlockStateModels.put(blockStateWrapper.registryId(), combinedVariant); JsonElement previous = overrideMap.get(propertyNBT); if (previous != null && !previous.equals(combinedVariant)) { throw new LocalizedResourceConfigException("warning.config.block.state.model.conflict", GsonHelper.get().toJson(combinedVariant), blockState, GsonHelper.get().toJson(previous)); } overrideMap.put(propertyNBT, combinedVariant); + AbstractBlockManager.this.tempVanillaBlockStateModels[blockStateWrapper.registryId()] = combinedVariant; } private JsonObject parseAppearanceModelSectionAsJson(Map section) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java index 7ce0ad545..4589397a0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockStateWrapper.java @@ -23,4 +23,16 @@ public abstract class AbstractBlockStateWrapper implements BlockStateWrapper { public String toString() { return this.blockState.toString(); } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof BlockStateWrapper that)) return false; + return this.registryId == that.registryId(); + } + + @Override + public int hashCode() { + return this.registryId; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java b/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java index b79a46f55..f917f72b4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AutoStateGroup.java @@ -1,6 +1,8 @@ package net.momirealms.craftengine.core.block; +import net.momirealms.craftengine.core.pack.allocator.BlockStateCandidate; import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; @@ -9,37 +11,68 @@ import java.util.function.Predicate; public enum AutoStateGroup { LEAVES("leaves", Set.of(BlockKeys.OAK_LEAVES, BlockKeys.SPRUCE_LEAVES, BlockKeys.BIRCH_LEAVES, BlockKeys.JUNGLE_LEAVES, BlockKeys.ACACIA_LEAVES, BlockKeys.DARK_OAK_LEAVES, BlockKeys.MANGROVE_LEAVES, BlockKeys.CHERRY_LEAVES, BlockKeys.PALE_OAK_LEAVES, BlockKeys.AZALEA_LEAVES, BlockKeys.FLOWERING_AZALEA_LEAVES), - (w) -> !(boolean) w.getProperty("waterlogged"), 0 + (w) -> !(boolean) w.getProperty("waterlogged") ), WATERLOGGED_LEAVES( "waterlogged_leaves", Set.of(BlockKeys.OAK_LEAVES, BlockKeys.SPRUCE_LEAVES, BlockKeys.BIRCH_LEAVES, BlockKeys.JUNGLE_LEAVES, BlockKeys.ACACIA_LEAVES, BlockKeys.DARK_OAK_LEAVES, BlockKeys.MANGROVE_LEAVES, BlockKeys.CHERRY_LEAVES, BlockKeys.PALE_OAK_LEAVES, BlockKeys.AZALEA_LEAVES, BlockKeys.FLOWERING_AZALEA_LEAVES), - (w) -> w.getProperty("waterlogged"), 0 + (w) -> w.getProperty("waterlogged") ), - TRIPWIRE("tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> true, 1), - LOWER_TRIPWIRE("lower_tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> w.getProperty("attached"), 0), - HIGHER_TRIPWIRE("higher_tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> !(boolean) w.getProperty("attached"), 0), - NOTE_BLOCK("note_block", Set.of(BlockKeys.NOTE_BLOCK), (w) -> true, 0), - BROWN_MUSHROOM("brown_mushroom", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK), (w) -> true, 0), - RED_MUSHROOM("red_mushroom", Set.of(BlockKeys.RED_MUSHROOM_BLOCK), (w) -> true, 0), - MUSHROOM_STEM("mushroom_stem", Set.of(BlockKeys.MUSHROOM_STEM), (w) -> true, 0), - MUSHROOM("mushroom", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK, BlockKeys.RED_MUSHROOM_BLOCK, BlockKeys.MUSHROOM_STEM), (w) -> true, 1), - SOLID("solid", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK, BlockKeys.RED_MUSHROOM_BLOCK, BlockKeys.MUSHROOM_STEM, BlockKeys.NOTE_BLOCK), (w) -> true, 2); + LOWER_TRIPWIRE("lower_tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> w.getProperty("attached")), + HIGHER_TRIPWIRE("higher_tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> !(boolean) w.getProperty("attached")), + NOTE_BLOCK("note_block", Set.of(BlockKeys.NOTE_BLOCK), (w) -> true), + BROWN_MUSHROOM("brown_mushroom", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK), (w) -> true), + RED_MUSHROOM("red_mushroom", Set.of(BlockKeys.RED_MUSHROOM_BLOCK), (w) -> true), + MUSHROOM_STEM("mushroom_stem", Set.of(BlockKeys.MUSHROOM_STEM), (w) -> true), + TRIPWIRE("tripwire", Set.of(BlockKeys.TRIPWIRE), (w) -> true), + SUGAR_CANE("sugar_cane", Set.of(BlockKeys.SUGAR_CANE), (w) -> true), + CACTUS("cactus", Set.of(BlockKeys.CACTUS), (w) -> true), + SAPLING("sapling", Set.of(BlockKeys.OAK_SAPLING, BlockKeys.SPRUCE_SAPLING, BlockKeys.BIRCH_SAPLING, BlockKeys.JUNGLE_SAPLING, BlockKeys.ACACIA_SAPLING, BlockKeys.DARK_OAK_SAPLING, BlockKeys.CHERRY_SAPLING, BlockKeys.PALE_OAK_SAPLING), (w) -> true), + MUSHROOM("mushroom", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK, BlockKeys.RED_MUSHROOM_BLOCK, BlockKeys.MUSHROOM_STEM), (w) -> true), + SOLID("solid", Set.of(BlockKeys.BROWN_MUSHROOM_BLOCK, BlockKeys.RED_MUSHROOM_BLOCK, BlockKeys.MUSHROOM_STEM, BlockKeys.NOTE_BLOCK), (w) -> true); private final Set blocks; private final String id; private final Predicate predicate; - private final int priority; + private final List candidates = new ArrayList<>(); + private int pointer; - AutoStateGroup(String id, Set blocks, Predicate predicate, int priority) { + AutoStateGroup(String id, Set blocks, Predicate predicate) { this.id = id; this.blocks = blocks; this.predicate = predicate; - this.priority = priority; } - public int priority() { - return priority; + public void reset() { + this.pointer = 0; + this.candidates.clear(); + } + + public void addCandidate(@NotNull BlockStateCandidate candidate) { + this.candidates.add(candidate); + } + + public int candidateCount() { + return candidates.size(); + } + + @Nullable + public BlockStateCandidate findNextCandidate() { + while (this.pointer < this.candidates.size()) { + final BlockStateCandidate state = this.candidates.get(this.pointer); + if (!state.isUsed()) { + return state; + } + this.pointer++; + } + return null; + } + + public boolean test(BlockStateWrapper state) { + if (!this.blocks.contains(state.ownerId())) { + return false; + } + return this.predicate.test(state); } public Set blocks() { 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 30490bbad..94bbf2342 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 @@ -7,6 +7,7 @@ import java.util.List; public final class BlockKeys { private BlockKeys() {} + public static final Key SUGAR_CANE = Key.of("minecraft:sugar_cane"); public static final Key NOTE_BLOCK = Key.of("minecraft:note_block"); public static final Key TRIPWIRE = Key.of("minecraft:tripwire"); public static final Key CRAFTING_TABLE = Key.of("minecraft:crafting_table"); @@ -262,6 +263,15 @@ public final class BlockKeys { public static final Key AZALEA_LEAVES = Key.of("minecraft:azalea_leaves"); public static final Key FLOWERING_AZALEA_LEAVES = Key.of("minecraft:flowering_azalea_leaves"); + public static final Key OAK_SAPLING = Key.of("minecraft:oak_sapling"); + public static final Key SPRUCE_SAPLING = Key.of("minecraft:spruce_sapling"); + public static final Key BIRCH_SAPLING = Key.of("minecraft:birch_sapling"); + public static final Key JUNGLE_SAPLING = Key.of("minecraft:jungle_sapling"); + public static final Key DARK_OAK_SAPLING = Key.of("minecraft:dark_oak_sapling"); + public static final Key ACACIA_SAPLING = Key.of("minecraft:acacia_sapling"); + public static final Key CHERRY_SAPLING = Key.of("minecraft:cherry_sapling"); + public static final Key PALE_OAK_SAPLING = Key.of("minecraft:pale_oak_sapling"); + public static final List WOODEN_TRAPDOORS = List.of(OAK_TRAPDOOR, SPRUCE_TRAPDOOR, BIRCH_TRAPDOOR, ACACIA_TRAPDOOR, PALE_OAK_TRAPDOOR, DARK_OAK_TRAPDOOR, MANGROVE_TRAPDOOR, JUNGLE_TRAPDOOR); public static final List CHERRY_TRAPDOORS = List.of(CHERRY_TRAPDOOR); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java index 0b19c2ee3..5ef5223b1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java @@ -1,8 +1,9 @@ package net.momirealms.craftengine.core.block; import net.momirealms.craftengine.core.util.Key; +import org.jetbrains.annotations.NotNull; -public interface BlockStateWrapper { +public interface BlockStateWrapper extends Comparable { Object literalObject(); @@ -15,4 +16,9 @@ public interface BlockStateWrapper { boolean hasProperty(String propertyName); String getAsString(); + + @Override + default int compareTo(@NotNull BlockStateWrapper o) { + return Integer.compare(registryId(), o.registryId()); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index f8ed7e7c3..5c44b4428 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -80,6 +80,16 @@ public abstract class AbstractFontManager implements FontManager { return offsetFont; } + @Override + public Map loadedImages() { + return Collections.unmodifiableMap(this.images); + } + + @Override + public Map emojis() { + return Collections.unmodifiableMap(this.emojis); + } + @Override public void unload() { this.fonts.clear(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java index e56e39c3b..7cf65807b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/FontManager.java @@ -48,6 +48,10 @@ public interface FontManager extends Manageable { OffsetFont offsetFont(); + Map loadedImages(); + + Map emojis(); + ConfigParser[] parsers(); default EmojiTextProcessResult replaceMiniMessageEmoji(@NotNull String miniMessage, @Nullable Player player) { 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 b1d0539ed..9d3c7b909 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 @@ -69,6 +69,14 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl ItemDataModifiers.init(); } + public ItemParser itemParser() { + return itemParser; + } + + public EquipmentParser equipmentParser() { + return equipmentParser; + } + protected static void registerVanillaItemExtraBehavior(ItemBehavior behavior, Key... items) { for (Key key : items) { VANILLA_ITEM_EXTRA_BEHAVIORS.computeIfAbsent(key, k -> new ArrayList<>()).add(behavior); 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 c4ed3e352..6ee669d9a 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,7 +5,6 @@ import com.google.common.collect.Multimap; import com.google.common.jimfs.Configuration; import com.google.common.jimfs.Jimfs; import com.google.gson.*; -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; @@ -27,7 +26,9 @@ import net.momirealms.craftengine.core.pack.obfuscation.ObfA; 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.*; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.config.ConfigParser; +import net.momirealms.craftengine.core.plugin.config.StringKeyConstructor; import net.momirealms.craftengine.core.plugin.locale.I18NData; import net.momirealms.craftengine.core.plugin.locale.LocalizedException; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; @@ -615,7 +616,10 @@ public abstract class AbstractPackManager implements PackManager { long o2 = System.nanoTime(); this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); for (ConfigParser parser : this.sortedParsers) { - if (!predicate.test(parser)) continue; + if (!predicate.test(parser)) { + parser.clear(); + continue; + } long t1 = System.nanoTime(); parser.preProcess(); parser.loadAll(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateAllocator.java deleted file mode 100644 index 5669d0b27..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/BlockStateAllocator.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.momirealms.craftengine.core.pack.allocator; - -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; - -public class BlockStateAllocator { - private final List blockStates = new ArrayList<>(); - private int pointer = 0; - private int max = -1; - - public void addCandidate(BlockStateCandidate state) { - this.blockStates.add(state); - this.max = this.blockStates.size() - 1; - } - - @Nullable - public BlockStateCandidate findNext() { - while (this.pointer < this.max) { - final BlockStateCandidate state = this.blockStates.get(this.pointer); - if (!state.isUsed()) { - return state; - } - this.pointer++; - } - return null; - } - - public void processPendingAllocations() { - - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java index 47c5e6bd3..9a84c875a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java @@ -152,7 +152,7 @@ public class IdAllocator { * @param shouldRemove 判断是否应该移除的谓词 * @return 被移除的ID数量 */ - public int cleanupUnusedIds(Predicate shouldRemove) { + public List cleanupUnusedIds(Predicate shouldRemove) { List idsToRemove = new ArrayList<>(); for (String id : this.cachedIdMap.keySet()) { if (shouldRemove.test(id)) { @@ -160,15 +160,13 @@ public class IdAllocator { } } - int removedCount = 0; for (String id : idsToRemove) { Integer removedId = this.cachedIdMap.remove(id); if (removedId != null && !this.forcedIdMap.containsValue(removedId)) { this.occupiedIdSet.clear(removedId); - removedCount++; } } - return removedCount; + return idsToRemove; } /** diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java new file mode 100644 index 000000000..ab7d7cd86 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java @@ -0,0 +1,152 @@ +package net.momirealms.craftengine.core.pack.allocator; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import net.momirealms.craftengine.core.block.AutoStateGroup; +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.util.FileUtils; +import net.momirealms.craftengine.core.util.GsonHelper; +import net.momirealms.craftengine.core.util.Pair; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +public class VisualBlockStateAllocator { + private final Path cacheFilePath; + private final Map cachedBlockStates = new HashMap<>(); + private final Map>> pendingAllocations = new LinkedHashMap<>(); + @SuppressWarnings("unchecked") + private final List>>[] pendingAllocationFutures = new List[AutoStateGroup.values().length]; + private final BlockStateCandidate[] candidates; + private final Function factory; + + public VisualBlockStateAllocator(Path cacheFilePath, BlockStateCandidate[] candidates, Function factory) { + this.cacheFilePath = cacheFilePath; + this.candidates = candidates; + this.factory = factory; + } + + public void reset() { + Arrays.fill(this.pendingAllocationFutures, new ArrayList<>()); + this.cachedBlockStates.clear(); + this.pendingAllocations.clear(); + } + + public CompletableFuture assignFixedBlockState(String name, BlockStateWrapper state) { + this.cachedBlockStates.remove(name); + BlockStateCandidate candidate = this.candidates[state.registryId()]; + if (candidate != null) { + candidate.setUsed(); + } + return CompletableFuture.completedFuture(state); + } + + public CompletableFuture requestAutoState(String name, AutoStateGroup group) { + CompletableFuture future = new CompletableFuture<>(); + this.pendingAllocations.put(name, new Pair<>(group, future)); + this.pendingAllocationFutures[group.ordinal()].add(Pair.of(name, future)); + return future; + } + + public void processPendingAllocations() { + // 先处理缓存的 + for (Map.Entry entry : this.cachedBlockStates.entrySet()) { + int registryId = entry.getValue().registryId(); + // 检查候选方块是否可用 + BlockStateCandidate candidate = this.candidates[registryId]; + if (candidate != null) { + // 未被使用 + if (!candidate.isUsed()) { + // 获取当前的安排任务 + Pair> pair = this.pendingAllocations.get(entry.getKey()); + // 如果候选满足组,那么直接允许起飞 + if (pair != null && pair.left().test(candidate.blockState())) { + pair.right().complete(candidate.blockState()); + } + // 尽管未被使用,该槽位也应该被占用,以避免被自动分配到 + candidate.setUsed(); + } + // 被使用了就随他去 + } + // 没有候选也随他去 + } + + this.pendingAllocations.clear(); + + for (AutoStateGroup group : AutoStateGroup.values()) { + List>> pendingAllocationFuture = this.pendingAllocationFutures[group.ordinal()]; + for (Pair> pair : pendingAllocationFuture) { + BlockStateCandidate nextCandidate = group.findNextCandidate(); + if (nextCandidate != null) { + nextCandidate.setUsed(); + this.cachedBlockStates.put(pair.left(), nextCandidate.blockState()); + pair.right().complete(nextCandidate.blockState()); + } else { + pair.right().completeExceptionally(new StateExhaustedException(group)); + } + } + } + } + + public static class StateExhaustedException extends RuntimeException { + private final AutoStateGroup group; + + public StateExhaustedException(AutoStateGroup group) { + this.group = group; + } + + public AutoStateGroup group() { + return group; + } + } + + /** + * 从文件加载缓存 + */ + public void loadFromCache() throws IOException { + if (!Files.exists(this.cacheFilePath)) { + return; + } + JsonElement element = GsonHelper.readJsonFile(this.cacheFilePath); + if (element instanceof JsonObject jsonObject) { + for (Map.Entry entry : jsonObject.entrySet()) { + if (entry.getValue() instanceof JsonPrimitive primitive) { + String id = primitive.getAsString(); + BlockStateWrapper state = this.factory.apply(id); + if (state != null) { + this.cachedBlockStates.put(entry.getKey(), state); + } + } + } + } + } + + /** + * 保存缓存到文件 + */ + public void saveToCache() throws IOException { + // 创建按ID排序的TreeMap + Map sortedById = new TreeMap<>(); + for (Map.Entry entry : this.cachedBlockStates.entrySet()) { + sortedById.put(entry.getValue(), entry.getKey()); + } + // 创建有序的JSON对象 + JsonObject sortedJsonObject = new JsonObject(); + for (Map.Entry entry : sortedById.entrySet()) { + sortedJsonObject.addProperty(entry.getValue(), entry.getKey().getAsString()); + } + if (sortedJsonObject.isEmpty()) { + if (Files.exists(this.cacheFilePath)) { + Files.delete(this.cacheFilePath); + } + } else { + FileUtils.createDirectoriesSafe(this.cacheFilePath.getParent()); + GsonHelper.writeJsonFile(sortedJsonObject, this.cacheFilePath); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/AllocationCacheFile.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/AllocationCacheFile.java new file mode 100644 index 000000000..4a636da69 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/AllocationCacheFile.java @@ -0,0 +1,62 @@ +package net.momirealms.craftengine.core.pack.allocator.cache; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; + +public class AllocationCacheFile, A> { + private final Map cache; + private final CacheStorage cacheStorage; + private final CacheSerializer serializer; + + public AllocationCacheFile(CacheStorage cacheStorage, CacheSerializer serializer) { + this.cache = new HashMap<>(); + this.cacheStorage = cacheStorage; + this.serializer = serializer; + } + + public Map cache() { + return this.cache; + } + + public void clear() { + this.cache.clear(); + } + + public CompletableFuture load() { + return this.cacheStorage.load().thenAccept(a -> { + Map deserialized = this.serializer.deserialize(a); + this.cache.putAll(deserialized); + }); + } + + public CompletableFuture save() { + Map sortedById = new TreeMap<>(); + for (Map.Entry entry : this.cache.entrySet()) { + sortedById.put(entry.getValue(), entry.getKey()); + } + return this.cacheStorage.save(this.serializer.serialize(sortedById)); + } + + public Iterable> entrySet() { + return this.cache.entrySet(); + } + + public Set keySet() { + return this.cache.keySet(); + } + + public void put(String name, T newId) { + this.cache.put(name, newId); + } + + public T remove(String name) { + return this.cache.remove(name); + } + + public T get(String name) { + return this.cache.get(name); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheFileStorage.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheFileStorage.java new file mode 100644 index 000000000..d230558fa --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheFileStorage.java @@ -0,0 +1,98 @@ +package net.momirealms.craftengine.core.pack.allocator.cache; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.CompletableFuture; + +public interface CacheFileStorage { + + CompletableFuture load(); + + CompletableFuture save(A value); + + boolean needForceUpdate(); + + static LocalFileCacheStorage local(Path path, CacheFileType type) { + return new LocalFileCacheStorage<>(path, type); + } + + abstract class AbstractRemoteFileCacheStorage implements CacheFileStorage { + + @Override + public boolean needForceUpdate() { + return true; + } + } + + class LocalFileCacheStorage implements CacheFileStorage { + private final CacheFileType fileType; + private final Path filePath; + private long lastModified = 0L; + + public LocalFileCacheStorage(Path filePath, CacheFileType type) { + this.filePath = filePath; + this.fileType = type; + updateLastModified(); + } + + @Override + public boolean needForceUpdate() { + try { + if (!Files.exists(this.filePath)) { + return this.lastModified != 0L; // 文件被删除了,需要更新 + } + long currentModified = Files.getLastModifiedTime(this.filePath).toMillis(); + if (currentModified > this.lastModified) { + this.lastModified = currentModified; + return true; // 文件被修改了,需要强制更新 + } + return false; + } catch (IOException e) { + // 如果无法读取文件信息,保守起见返回 true 强制更新 + return true; + } + } + + @Override + public CompletableFuture load() { + if (!Files.exists(this.filePath)) { + this.lastModified = 0L; // 重置最后修改时间 + return CompletableFuture.completedFuture(this.fileType.create()); + } + try { + A result = this.fileType.read(this.filePath); + updateLastModified(); // 加载成功后更新最后修改时间 + return CompletableFuture.completedFuture(result); + } catch (Exception e) { + return CompletableFuture.failedFuture(e); + } + } + + @Override + public CompletableFuture save(A value) { + try { + this.fileType.write(this.filePath, value); + updateLastModified(); // 保存成功后更新最后修改时间 + return CompletableFuture.completedFuture(null); + } catch (Exception e) { + return CompletableFuture.failedFuture(e); + } + } + + /** + * 更新最后修改时间 + */ + private void updateLastModified() { + try { + if (Files.exists(this.filePath)) { + this.lastModified = Files.getLastModifiedTime(filePath).toMillis(); + } else { + this.lastModified = 0L; + } + } catch (IOException e) { + this.lastModified = 0L; // 出错时重置 + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheFileType.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheFileType.java new file mode 100644 index 000000000..b4446a511 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheFileType.java @@ -0,0 +1,39 @@ +package net.momirealms.craftengine.core.pack.allocator.cache; + +import com.google.gson.JsonObject; +import net.momirealms.craftengine.core.util.GsonHelper; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public interface CacheFileType { + JsonCacheFileType JSON = new JsonCacheFileType(); + + T read(Path path) throws IOException; + + void write(Path path, T value) throws IOException; + + T create(); + + class JsonCacheFileType implements CacheFileType { + + @Override + public JsonObject read(Path path) throws IOException { + if (Files.exists(path)) { + return GsonHelper.readJsonFile(path).getAsJsonObject(); + } + return new JsonObject(); + } + + @Override + public void write(Path path, JsonObject value) throws IOException { + GsonHelper.writeJsonFile(value, path); + } + + @Override + public JsonObject create() { + return new JsonObject(); + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheSerializer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheSerializer.java new file mode 100644 index 000000000..161caad29 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheSerializer.java @@ -0,0 +1,51 @@ +package net.momirealms.craftengine.core.pack.allocator.cache; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; + +import java.util.HashMap; +import java.util.Map; + +public interface CacheSerializer, A> { + + A serialize(Map obj); + + Map deserialize(A obj); + + static > CacheSerializer json() { + return new JsonSerializer<>(); + } + + class JsonSerializer> implements CacheSerializer { + + @Override + public JsonObject serialize(Map obj) { + JsonObject jsonObject = new JsonObject(); + for (Map.Entry entry : obj.entrySet()) { + if (entry.getKey() instanceof Integer i) { + jsonObject.addProperty(entry.getValue(), i); + } else if (entry.getKey() instanceof String s) { + jsonObject.addProperty(entry.getValue(), s); + } + } + return jsonObject; + } + + @SuppressWarnings("unchecked") + @Override + public Map deserialize(JsonObject obj) { + Map map = new HashMap<>(); + for (Map.Entry entry : obj.entrySet()) { + if (entry.getValue() instanceof JsonPrimitive primitive) { + if (primitive.isNumber()) { + map.put(entry.getKey(), (T) (Integer) primitive.getAsInt()); + } else if (primitive.isString()) { + map.put(entry.getKey(), (T) primitive.getAsString()); + } + } + } + return map; + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheStorage.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheStorage.java new file mode 100644 index 000000000..10856d762 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/cache/CacheStorage.java @@ -0,0 +1,32 @@ +package net.momirealms.craftengine.core.pack.allocator.cache; + +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.CompletableFuture; + +public class CacheStorage { + private final CacheFileStorage storage; + private A lastReadValue; + + public CacheStorage(CacheFileStorage storage) { + this.storage = storage; + } + + public CompletableFuture save(@NotNull final A value) { + if (!value.equals(this.lastReadValue) || this.storage.needForceUpdate()) { + this.lastReadValue = value; + return this.storage.save(value); + } + return CompletableFuture.completedFuture(null); + } + + public CompletableFuture load() { + if (this.lastReadValue != null && !this.storage.needForceUpdate()) { + return CompletableFuture.completedFuture(this.lastReadValue); + } + return this.storage.load().thenApply(a -> { + this.lastReadValue = a; + return a; + }); + } +} From ba1fef4de77208178e495581c9b24693d88d9943 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Tue, 30 Sep 2025 01:20:32 +0800 Subject: [PATCH 091/125] =?UTF-8?q?=E7=AE=80=E6=98=93=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/blocks/hami_melon.yml | 2 +- .../core/block/AbstractBlockManager.java | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml index 46e1b51e7..00cc12d7c 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/hami_melon.yml @@ -79,7 +79,7 @@ blocks: - minecraft:mineable/axe - minecraft:sword_efficient state: - state: note_block:30 + auto-state: solid model: template: default:model/cube arguments: diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 8f0af28ff..cd43c04cd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -315,29 +315,29 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem @Override public void postProcess() { - this.visualBlockStateAllocator.processPendingAllocations(); - try { - this.visualBlockStateAllocator.saveToCache(); - } catch (IOException e) { - AbstractBlockManager.this.plugin.logger().warn("Error while saving visual block states allocation", e); - } this.internalIdAllocator.processPendingAllocations(); try { this.internalIdAllocator.saveToCache(); } catch (IOException e) { AbstractBlockManager.this.plugin.logger().warn("Error while saving custom block states allocation", e); } + this.visualBlockStateAllocator.processPendingAllocations(); + try { + this.visualBlockStateAllocator.saveToCache(); + } catch (IOException e) { + AbstractBlockManager.this.plugin.logger().warn("Error while saving visual block states allocation", e); + } } @Override public void preProcess() { + this.internalIdAllocator.reset(0, Config.serverSideBlocks() - 1); this.visualBlockStateAllocator.reset(); try { this.visualBlockStateAllocator.loadFromCache(); } catch (IOException e) { AbstractBlockManager.this.plugin.logger().warn("Error while loading visual block states allocation cache", e); } - this.internalIdAllocator.reset(0, Config.serverSideBlocks() - 1); try { this.internalIdAllocator.loadFromCache(); } catch (IOException e) { @@ -498,8 +498,8 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem appearanceName, this.visualBlockStateAllocator.assignFixedBlockState(appearanceName.isEmpty() ? id.asString() : id.asString() + ":" + appearanceName, parsePluginFormattedBlockState(appearanceSection.get("state").toString())) ); - } else if (stateSection.containsKey("auto-state")) { - String autoStateId = stateSection.get("auto-state").toString(); + } else if (appearanceSection.containsKey("auto-state")) { + String autoStateId = appearanceSection.get("auto-state").toString(); AutoStateGroup group = AutoStateGroup.byId(autoStateId); if (group == null) { throw new LocalizedResourceConfigException("warning.config.block.state.invalid_auto_state", autoStateId, EnumUtils.toString(AutoStateGroup.values())); From eda7ff749d92c94c518bc3d7fecbc96576043105 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Tue, 30 Sep 2025 02:44:14 +0800 Subject: [PATCH 092/125] =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/DebugCleanCacheCommand.java | 170 ++++++++++++++++-- .../src/main/resources/translations/en.yml | 2 +- .../core/block/AbstractBlockManager.java | 12 +- .../core/font/AbstractFontManager.java | 5 +- .../allocator/VisualBlockStateAllocator.java | 35 +++- 5 files changed, 198 insertions(+), 26 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java index 8337140f6..d6b01bcd3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java @@ -1,14 +1,22 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; -import net.momirealms.craftengine.bukkit.api.CraftEngineItems; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.font.BukkitFontManager; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +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.font.BitmapImage; +import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.pack.allocator.IdAllocator; +import net.momirealms.craftengine.core.pack.allocator.VisualBlockStateAllocator; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.util.FileUtils; import net.momirealms.craftengine.core.util.Key; import org.bukkit.command.CommandSender; +import org.bukkit.inventory.ItemStack; import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; import org.incendo.cloud.context.CommandContext; @@ -18,11 +26,11 @@ import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; import java.io.IOException; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; +import java.util.stream.Stream; public class DebugCleanCacheCommand extends BukkitCommandFeature { @@ -48,9 +56,14 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature switch (type) { case "custom-model-data" -> { BukkitItemManager instance = BukkitItemManager.instance(); - Set ids = CraftEngineItems.loadedItems().keySet().stream().map(Key::toString).collect(Collectors.toSet()); + Map> idsMap = new HashMap<>(); + for (CustomItem item : instance.loadedItems().values()) { + Set ids = idsMap.computeIfAbsent(item.clientBoundMaterial(), k -> new HashSet<>()); + ids.add(item.id().asString()); + } int total = 0; - for (Map.Entry entry : instance.itemParser().idAllocators().entrySet()) { + for (Map.Entry entry : getAllCachedCustomModelData().entrySet()) { + Set ids = idsMap.getOrDefault(entry.getKey(), Collections.emptySet()); List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); total += removed.size(); try { @@ -60,18 +73,82 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature return; } for (String id : removed) { - this.plugin().logger().info("Cleaned unused item: " + id); + this.plugin().logger().info("Cleaned unsued item: " + id); } } context.sender().sendMessage("Cleaned " + total + " unused custom model data"); } - case "custom-block-states" -> { - } - case "visual-block-states" -> { - } case "font", "images" -> { BukkitFontManager instance = this.plugin().fontManager(); - + Map> idsMap = new HashMap<>(); + for (BitmapImage image : instance.loadedImages().values()) { + Set ids = idsMap.computeIfAbsent(image.font(), k -> new HashSet<>()); + String id = image.id().toString(); + ids.add(id); + for (int i = 0; i < image.rows(); i++) { + for (int j = 0; j < image.columns(); j++) { + String imageArgs = id + ":" + i + ":" + j; + ids.add(imageArgs); + } + } + } + int total = 0; + for (Map.Entry entry : getAllCachedFont().entrySet()) { + Key font = entry.getKey(); + Set ids = idsMap.getOrDefault(font, Collections.emptySet()); + List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); + try { + entry.getValue().saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving codepoint allocation for font " + font.asString(), e); + return; + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued image: " + id); + } + total += removed.size(); + } + context.sender().sendMessage("Cleaned " + total + " unused codepoints"); + } + case "custom-block-states" -> { + BukkitBlockManager instance = BukkitBlockManager.instance(); + Set ids = new HashSet<>(); + for (CustomBlock customBlock : instance.loadedBlocks().values()) { + for (ImmutableBlockState state : customBlock.variantProvider().states()) { + ids.add(state.toString()); + } + } + IdAllocator idAllocator = instance.blockParser().internalIdAllocator(); + List removed = idAllocator.cleanupUnusedIds(i -> !ids.contains(i)); + try { + idAllocator.saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving custom block states allocation", e); + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued block state: " + id); + } + context.sender().sendMessage("Cleaned " + removed.size() + " unused custom block states"); + } + case "visual-block-states" -> { + BukkitBlockManager instance = BukkitBlockManager.instance(); + Set ids = new HashSet<>(); + for (CustomBlock customBlock : instance.loadedBlocks().values()) { + for (ImmutableBlockState state : customBlock.variantProvider().states()) { + ids.add(state.vanillaBlockState()); + } + } + VisualBlockStateAllocator visualBlockStateAllocator = instance.blockParser().visualBlockStateAllocator(); + List removed = visualBlockStateAllocator.cleanupUnusedIds(i -> !ids.contains(i)); + try { + visualBlockStateAllocator.saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving visual block states allocation", e); + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued block appearance: " + id); + } + context.sender().sendMessage("Cleaned " + removed.size() + " unused block state appearances"); } } }); @@ -81,4 +158,71 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature public String getFeatureID() { return "debug_clean_cache"; } + + public Map getAllCachedCustomModelData() { + Path cacheDir = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("custom-model-data"); + + Map idAllocators = new HashMap<>(); + try (Stream files = Files.list(cacheDir)) { + files.filter(this::isJsonFile) + .forEach(file -> processIdAllocatorFile(cacheDir, file, idAllocators)); + + } catch (IOException e) { + CraftEngine.instance().logger().warn("Failed to process: " + cacheDir.getFileName(), e); + } + + return idAllocators; + } + + public Map getAllCachedFont() { + Path cacheDir = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("font"); + + try { + List namespaces = FileUtils.collectNamespaces(cacheDir); + Map idAllocators = new HashMap<>(); + + for (Path namespace : namespaces) { + processNamespace(namespace, idAllocators); + } + return idAllocators; + + } catch (IOException e) { + CraftEngine.instance().logger().warn("Failed to load cached id allocators from: " + cacheDir, e); + return Collections.emptyMap(); + } + } + + private void processNamespace(Path namespace, Map idAllocators) { + if (!Files.isDirectory(namespace)) { + return; + } + + try (Stream files = Files.list(namespace)) { + files.filter(this::isJsonFile) + .forEach(file -> processIdAllocatorFile(namespace, file, idAllocators)); + + } catch (IOException e) { + CraftEngine.instance().logger().warn("Failed to process namespace: " + namespace.getFileName(), e); + } + } + + private boolean isJsonFile(Path file) { + return Files.isRegularFile(file) && file.getFileName().toString().endsWith(".json"); + } + + private void processIdAllocatorFile(Path namespace, Path file, Map idAllocators) { + try { + String namespaceName = namespace.getFileName().toString(); + String fileName = FileUtils.pathWithoutExtension(file.getFileName().toString()); + + Key font = Key.of(namespaceName, fileName); + IdAllocator allocator = new IdAllocator(file); + allocator.loadFromCache(); + + idAllocators.put(font, allocator); + + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to load id allocator from: " + file, e); + } + } } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index acd02e1a4..2c0551596 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -278,7 +278,7 @@ warning.config.block.state.entity_renderer.model_engine.missing_model: " warning.config.block.state.variant.invalid_appearance: "Issue found in file - The block '' has an error that the variant '' is using a non-existing appearance ''." warning.config.block.state.invalid_vanilla: "Issue found in file - The block '' is using an invalid vanilla block state ''." warning.config.block.state.invalid_auto_state: "Issue found in file - The block '' is using an invalid auto-state ''. Allowed values: []." -warning.config.block.state.auto_state.exhausted: "Issue found in file - Cannot allocate visual block state for block '' as the slots('') in group '' have been exhausted." +warning.config.block.state.auto_state.exhausted: "Issue found in file - The visual state group '' has reached its maximum capacity of '' slots and cannot allocate a state for block ''." warning.config.block.state.unavailable_vanilla: "Issue found in file - The block '' is using an unavailable vanilla block state ''. Please free that state in block-state-mappings." warning.config.block.state.invalid_vanilla_id: "Issue found in file - The block '' is using a vanilla block state '' that exceeds the available slot range '0~'." warning.config.block.state.invalid_id: "Issue found in file - The block state ID range () used by block '' is outside the valid range of 0 to . Please add more server-side blocks in 'config.yml' if the current slots are exhausted." diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index cd43c04cd..9fcd76918 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -313,6 +313,14 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem this.pendingConfigSections.add(section); } + public IdAllocator internalIdAllocator() { + return internalIdAllocator; + } + + public VisualBlockStateAllocator visualBlockStateAllocator() { + return visualBlockStateAllocator; + } + @Override public void postProcess() { this.internalIdAllocator.processPendingAllocations(); @@ -514,7 +522,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem } } - CompletableFutures.allOf(futureVisualStates.values()).whenComplete((v2, t2) -> { + CompletableFutures.allOf(futureVisualStates.values()).whenComplete((v2, t2) -> ResourceConfigUtils.runCatching(path, node, () -> { if (t2 != null) { if (t2 instanceof CompletionException e) { Throwable cause = e.getCause(); @@ -635,7 +643,7 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem // 抛出次要警告 exceptionCollector.throwIfPresent(); - }); + }, () -> GsonHelper.get().toJson(section))); }, () -> GsonHelper.get().toJson(section))); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index 5c44b4428..f7a3f02b9 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -32,6 +32,7 @@ import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.stream.Stream; public abstract class AbstractFontManager implements FontManager { private final CraftEngine plugin; @@ -511,10 +512,6 @@ public abstract class AbstractFontManager implements FontManager { }); } - public Map idAllocators() { - return this.idAllocators; - } - @Override public void parseSection(Pack pack, Path path, String node, Key id, Map section) { if (AbstractFontManager.this.images.containsKey(id)) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java index ab7d7cd86..db4576bd0 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.core.pack.allocator; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; @@ -15,6 +17,7 @@ import java.nio.file.Path; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.function.Function; +import java.util.function.Predicate; public class VisualBlockStateAllocator { private final Path cacheFilePath; @@ -32,7 +35,9 @@ public class VisualBlockStateAllocator { } public void reset() { - Arrays.fill(this.pendingAllocationFutures, new ArrayList<>()); + for (int i = 0; i < this.pendingAllocationFutures.length; i++) { + this.pendingAllocationFutures[i] = new ArrayList<>(); + } this.cachedBlockStates.clear(); this.pendingAllocations.clear(); } @@ -53,6 +58,19 @@ public class VisualBlockStateAllocator { return future; } + public List cleanupUnusedIds(Predicate shouldRemove) { + List idsToRemove = new ArrayList<>(); + for (Map.Entry entry : this.cachedBlockStates.entrySet()) { + if (shouldRemove.test(entry.getValue())) { + idsToRemove.add(entry.getKey()); + } + } + for (String id : idsToRemove) { + this.cachedBlockStates.remove(id); + } + return idsToRemove; + } + public void processPendingAllocations() { // 先处理缓存的 for (Map.Entry entry : this.cachedBlockStates.entrySet()) { @@ -64,12 +82,17 @@ public class VisualBlockStateAllocator { if (!candidate.isUsed()) { // 获取当前的安排任务 Pair> pair = this.pendingAllocations.get(entry.getKey()); - // 如果候选满足组,那么直接允许起飞 - if (pair != null && pair.left().test(candidate.blockState())) { - pair.right().complete(candidate.blockState()); + if (pair != null) { + // 如果候选满足组,那么直接允许起飞 + if (pair.left().test(candidate.blockState())) { + pair.right().complete(candidate.blockState()); + } else { + // 不满足候选组要求,那就等着分配新的吧 + } + } else { + // 尽管未被使用,该槽位也应该被占用,以避免被自动分配到 + candidate.setUsed(); } - // 尽管未被使用,该槽位也应该被占用,以避免被自动分配到 - candidate.setUsed(); } // 被使用了就随他去 } From fec7dfe47335f7775af0aa11b8db9ff348f033f1 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Tue, 30 Sep 2025 02:56:34 +0800 Subject: [PATCH 093/125] Update DebugCleanCacheCommand.java --- .../plugin/command/feature/DebugCleanCacheCommand.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java index d6b01bcd3..2371f0c9f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java @@ -13,6 +13,7 @@ import net.momirealms.craftengine.core.pack.allocator.IdAllocator; import net.momirealms.craftengine.core.pack.allocator.VisualBlockStateAllocator; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.FileUtils; import net.momirealms.craftengine.core.util.Key; import org.bukkit.command.CommandSender; @@ -165,7 +166,7 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature Map idAllocators = new HashMap<>(); try (Stream files = Files.list(cacheDir)) { files.filter(this::isJsonFile) - .forEach(file -> processIdAllocatorFile(cacheDir, file, idAllocators)); + .forEach(file -> processIdAllocatorFile("minecraft", file, idAllocators)); } catch (IOException e) { CraftEngine.instance().logger().warn("Failed to process: " + cacheDir.getFileName(), e); @@ -199,7 +200,7 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature try (Stream files = Files.list(namespace)) { files.filter(this::isJsonFile) - .forEach(file -> processIdAllocatorFile(namespace, file, idAllocators)); + .forEach(file -> processIdAllocatorFile(namespace.getFileName().toString(), file, idAllocators)); } catch (IOException e) { CraftEngine.instance().logger().warn("Failed to process namespace: " + namespace.getFileName(), e); @@ -210,9 +211,8 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature return Files.isRegularFile(file) && file.getFileName().toString().endsWith(".json"); } - private void processIdAllocatorFile(Path namespace, Path file, Map idAllocators) { + private void processIdAllocatorFile(String namespaceName, Path file, Map idAllocators) { try { - String namespaceName = namespace.getFileName().toString(); String fileName = FileUtils.pathWithoutExtension(file.getFileName().toString()); Key font = Key.of(namespaceName, fileName); From bf8e4afd0ba62ecae71a8b87737ed63675065194 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Tue, 30 Sep 2025 03:21:19 +0800 Subject: [PATCH 094/125] =?UTF-8?q?=E5=AE=8C=E5=96=84debug=E6=8C=87?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DebugAppearanceStateUsageCommand.java | 113 ++++++++++-------- .../feature/DebugCleanCacheCommand.java | 1 - .../feature/DebugRealStateUsageCommand.java | 75 ++++++------ common-files/src/main/resources/commands.yml | 2 + .../configuration/blocks/topaz_ore.yml | 2 +- .../core/block/AbstractBlockManager.java | 5 +- .../core/font/AbstractFontManager.java | 1 - .../core/pack/allocator/IdAllocator.java | 4 + .../allocator/VisualBlockStateAllocator.java | 9 +- 9 files changed, 121 insertions(+), 91 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java index 2192b12d4..78b10ff30 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugAppearanceStateUsageCommand.java @@ -1,10 +1,27 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.pack.allocator.VisualBlockStateAllocator; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.util.Key; import org.bukkit.command.CommandSender; +import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; +import org.incendo.cloud.context.CommandContext; +import org.incendo.cloud.context.CommandInput; +import org.incendo.cloud.parser.standard.StringParser; +import org.incendo.cloud.suggestion.Suggestion; +import org.incendo.cloud.suggestion.SuggestionProvider; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; public class DebugAppearanceStateUsageCommand extends BukkitCommandFeature { @@ -15,54 +32,56 @@ public class DebugAppearanceStateUsageCommand extends BukkitCommandFeature assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder -// .required("id", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { -// @Override -// public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { -// return CompletableFuture.completedFuture(plugin().blockManager().blockAppearanceArranger().keySet().stream().map(it -> Suggestion.suggestion(it.toString())).toList()); -// } -// })) + .required("id", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(plugin().blockManager().blockStateArranger().keySet().stream().map(it -> Suggestion.suggestion(it.toString())).toList()); + } + })) .handler(context -> { -// String data = context.get("id"); -// BukkitBlockManager blockManager = plugin().blockManager(); -// Key baseBlockId = Key.of(data); -// List appearances = blockManager.blockAppearanceArranger().get(baseBlockId); -// if (appearances == null) return; -// int i = 0; -// Component block = Component.text(baseBlockId + ": "); -// plugin().senderFactory().wrap(context.sender()).sendMessage(block); -// -// List batch = new ArrayList<>(); -// for (int appearance : appearances) { -// Component text = Component.text("|"); -// List reals = blockManager.appearanceToRealStates(appearance); -// if (reals == null || reals.isEmpty()) { -// Component hover = Component.text(baseBlockId.value() + ":" + i).color(NamedTextColor.GREEN); -// hover = hover.append(Component.newline()).append(Component.text(BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(appearance)).getAsString()).color(NamedTextColor.GREEN)); -// text = text.color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover)); -// } else { -// Component hover = Component.text(baseBlockId.value() + ":" + i).color(NamedTextColor.RED); -// List hoverChildren = new ArrayList<>(); -// hoverChildren.add(Component.newline()); -// hoverChildren.add(Component.text(BlockStateUtils.fromBlockData(BlockStateUtils.idToBlockState(appearance)).getAsString()).color(NamedTextColor.RED)); -// for (int real : reals) { -// hoverChildren.add(Component.newline()); -// hoverChildren.add(Component.text(blockManager.getImmutableBlockStateUnsafe(real).toString()).color(NamedTextColor.GRAY)); -// } -// text = text.color(NamedTextColor.RED).hoverEvent(HoverEvent.showText(hover.children(hoverChildren))); -// } -// batch.add(text); -// i++; -// if (batch.size() == 100) { -// plugin().senderFactory().wrap(context.sender()) -// .sendMessage(Component.text("").children(batch)); -// batch.clear(); -// } -// } -// if (!batch.isEmpty()) { -// plugin().senderFactory().wrap(context.sender()) -// .sendMessage(Component.text("").children(batch)); -// batch.clear(); -// } + String data = context.get("id"); + BukkitBlockManager blockManager = plugin().blockManager(); + Key baseBlockId = Key.of(data); + List appearances = blockManager.blockStateArranger().get(baseBlockId); + if (appearances == null) return; + int i = 0; + Component block = Component.text(baseBlockId + ": "); + plugin().senderFactory().wrap(context.sender()).sendMessage(block); + VisualBlockStateAllocator allocator = blockManager.blockParser().visualBlockStateAllocator(); + List batch = new ArrayList<>(); + for (BlockStateWrapper appearance : appearances) { + Component text = Component.text("|"); + List reals = blockManager.appearanceToRealStates(appearance.registryId()); + if (reals.isEmpty()) { + Component hover = Component.text(baseBlockId.value() + ":" + i).color(NamedTextColor.GREEN); + hover = hover.append(Component.newline()).append(Component.text(appearance.getAsString()).color(NamedTextColor.GREEN)); + text = text.color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover)); + } else { + boolean isFixed = allocator.isForcedState(appearance); + NamedTextColor namedTextColor = isFixed ? NamedTextColor.RED : NamedTextColor.YELLOW; + Component hover = Component.text(baseBlockId.value() + ":" + i).color(namedTextColor); + List hoverChildren = new ArrayList<>(); + hoverChildren.add(Component.newline()); + hoverChildren.add(Component.text(appearance.getAsString()).color(namedTextColor)); + for (int real : reals) { + hoverChildren.add(Component.newline()); + hoverChildren.add(Component.text(blockManager.getImmutableBlockStateUnsafe(real).toString()).color(NamedTextColor.GRAY)); + } + text = text.color(namedTextColor).hoverEvent(HoverEvent.showText(hover.children(hoverChildren))); + } + batch.add(text); + i++; + if (batch.size() == 100) { + plugin().senderFactory().wrap(context.sender()) + .sendMessage(Component.text("").children(batch)); + batch.clear(); + } + } + if (!batch.isEmpty()) { + plugin().senderFactory().wrap(context.sender()) + .sendMessage(Component.text("").children(batch)); + batch.clear(); + } }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java index 2371f0c9f..3c3ad6ed7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java @@ -13,7 +13,6 @@ import net.momirealms.craftengine.core.pack.allocator.IdAllocator; import net.momirealms.craftengine.core.pack.allocator.VisualBlockStateAllocator; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.FileUtils; import net.momirealms.craftengine.core.util.Key; import org.bukkit.command.CommandSender; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java index d30863b8c..14e9888d9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugRealStateUsageCommand.java @@ -1,11 +1,22 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.format.NamedTextColor; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.core.block.BlockManager; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.pack.allocator.IdAllocator; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +import net.momirealms.craftengine.core.plugin.config.Config; import org.bukkit.command.CommandSender; import org.incendo.cloud.Command; +import java.util.ArrayList; +import java.util.List; + public class DebugRealStateUsageCommand extends BukkitCommandFeature { public DebugRealStateUsageCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { @@ -15,45 +26,33 @@ public class DebugRealStateUsageCommand extends BukkitCommandFeature assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder -// .required("id", StringParser.stringComponent(StringParser.StringMode.GREEDY_FLAG_YIELDING).suggestionProvider(new SuggestionProvider<>() { -// @Override -// public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { -// return CompletableFuture.completedFuture(plugin().blockManager().blockAppearanceArranger().keySet().stream().map(it -> Suggestion.suggestion(it.toString())).toList()); -// } -// })) .handler(context -> { -// String data = context.get("id"); -// BukkitBlockManager blockManager = plugin().blockManager(); -// Key baseBlockId = Key.of(data); -// List reals = blockManager.realBlockArranger().get(baseBlockId); -// if (reals == null) return; -// int i = 0; -// Component block = Component.text(baseBlockId + ": "); -// plugin().senderFactory().wrap(context.sender()).sendMessage(block); -// -// List batch = new ArrayList<>(100); -// for (int real : reals) { -// ImmutableBlockState state = blockManager.getImmutableBlockStateUnsafe(real); -// if (state.isEmpty()) { -// Component hover = Component.text("craftengine:" + baseBlockId.value() + "_" + i).color(NamedTextColor.GREEN); -// batch.add(Component.text("|").color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover))); -// } else { -// Component hover = Component.text("craftengine:" + baseBlockId.value() + "_" + i).color(NamedTextColor.RED); -// hover = hover.append(Component.newline()).append(Component.text(state.toString()).color(NamedTextColor.GRAY)); -// batch.add(Component.text("|").color(NamedTextColor.RED).hoverEvent(HoverEvent.showText(hover))); -// } -// i++; -// if (batch.size() == 100) { -// plugin().senderFactory().wrap(context.sender()) -// .sendMessage(Component.text("").children(batch)); -// batch.clear(); -// } -// } -// if (!batch.isEmpty()) { -// plugin().senderFactory().wrap(context.sender()) -// .sendMessage(Component.text("").children(batch)); -// batch.clear(); -// } + BukkitBlockManager blockManager = plugin().blockManager(); + plugin().senderFactory().wrap(context.sender()).sendMessage(Component.text("Serverside block state usage:")); + List batch = new ArrayList<>(100); + IdAllocator idAllocator = blockManager.blockParser().internalIdAllocator(); + for (int i = 0; i < Config.serverSideBlocks(); i++) { + ImmutableBlockState state = blockManager.getImmutableBlockStateUnsafe(i + blockManager.vanillaBlockStateCount()); + if (state.isEmpty()) { + Component hover = Component.text(BlockManager.createCustomBlockKey(i).asString()).color(NamedTextColor.GREEN); + batch.add(Component.text("|").color(NamedTextColor.GREEN).hoverEvent(HoverEvent.showText(hover))); + } else { + NamedTextColor namedTextColor = idAllocator.isForced(state.toString()) ? NamedTextColor.RED : NamedTextColor.YELLOW; + Component hover = Component.text(BlockManager.createCustomBlockKey(i).asString()).color(namedTextColor); + hover = hover.append(Component.newline()).append(Component.text(state.toString()).color(NamedTextColor.GRAY)); + batch.add(Component.text("|").color(namedTextColor).hoverEvent(HoverEvent.showText(hover))); + } + if (batch.size() == 100) { + plugin().senderFactory().wrap(context.sender()) + .sendMessage(Component.text("").children(batch)); + batch.clear(); + } + } + if (!batch.isEmpty()) { + plugin().senderFactory().wrap(context.sender()) + .sendMessage(Component.text("").children(batch)); + batch.clear(); + } }); } diff --git a/common-files/src/main/resources/commands.yml b/common-files/src/main/resources/commands.yml index 9ba12ceeb..a96b802e0 100644 --- a/common-files/src/main/resources/commands.yml +++ b/common-files/src/main/resources/commands.yml @@ -152,7 +152,9 @@ debug_real_state_usage: permission: ce.command.debug.state_usage usage: - /craftengine debug real-state-usage + - /craftengine debug serverside-state-usage - /ce debug real-state-usage + - /ce debug serverside-state-usage debug_item_data: enable: true diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml b/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml index 6721d3027..f120a9776 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/topaz_ore.yml @@ -68,7 +68,7 @@ blocks: arguments: break_power: 2 state: - state: note_block:14 + auto-state: solid model: template: default:model/simplified_cube_all arguments: diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java index 9fcd76918..86719197c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/AbstractBlockManager.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.core.block; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -155,6 +154,10 @@ public abstract class AbstractBlockManager extends AbstractModelGenerator implem return Optional.ofNullable(this.byId.get(id)); } + public Map> blockStateArranger() { + return this.blockStateArranger; + } + protected abstract void applyPlatformSettings(ImmutableBlockState state); @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java index f7a3f02b9..639076b6c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -32,7 +32,6 @@ import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import java.util.stream.Stream; public abstract class AbstractFontManager implements FontManager { private final CraftEngine plugin; diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java index 9a84c875a..b8657238e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java @@ -124,6 +124,10 @@ public class IdAllocator { return CompletableFuture.completedFuture(id); } + public boolean isForced(String name) { + return this.forcedIdMap.containsKey(name); + } + public List> getFixedIdsBetween(int minId, int maxId) { BiMap inverse = this.forcedIdMap.inverse(); List> result = new ArrayList<>(); diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java index db4576bd0..7138465fa 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java @@ -1,7 +1,5 @@ package net.momirealms.craftengine.core.pack.allocator; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; @@ -27,6 +25,7 @@ public class VisualBlockStateAllocator { private final List>>[] pendingAllocationFutures = new List[AutoStateGroup.values().length]; private final BlockStateCandidate[] candidates; private final Function factory; + private final Set forcedStates = new HashSet<>(); public VisualBlockStateAllocator(Path cacheFilePath, BlockStateCandidate[] candidates, Function factory) { this.cacheFilePath = cacheFilePath; @@ -40,10 +39,16 @@ public class VisualBlockStateAllocator { } this.cachedBlockStates.clear(); this.pendingAllocations.clear(); + this.forcedStates.clear(); + } + + public boolean isForcedState(final BlockStateWrapper state) { + return this.forcedStates.contains(state); } public CompletableFuture assignFixedBlockState(String name, BlockStateWrapper state) { this.cachedBlockStates.remove(name); + this.forcedStates.add(state); BlockStateCandidate candidate = this.candidates[state.registryId()]; if (candidate != null) { candidate.setUsed(); From aa5e58fb266318c2c080b8d89edd41e165ee73e3 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Tue, 30 Sep 2025 11:24:13 +0800 Subject: [PATCH 095/125] =?UTF-8?q?fix(core):=20=E4=BF=AE=E5=A4=8D1.20?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../momirealms/craftengine/core/pack/allocator/IdAllocator.java | 2 +- .../core/pack/allocator/VisualBlockStateAllocator.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java index b8657238e..3a42d71ed 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/IdAllocator.java @@ -235,7 +235,7 @@ public class IdAllocator { sortedJsonObject.addProperty(entry.getValue(), entry.getKey()); } - if (sortedJsonObject.isEmpty()) { + if (sortedJsonObject.asMap().isEmpty()) { if (Files.exists(this.cacheFilePath)) { Files.delete(this.cacheFilePath); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java index 7138465fa..7087b55d2 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java @@ -168,7 +168,7 @@ public class VisualBlockStateAllocator { for (Map.Entry entry : sortedById.entrySet()) { sortedJsonObject.addProperty(entry.getValue(), entry.getKey().getAsString()); } - if (sortedJsonObject.isEmpty()) { + if (sortedJsonObject.asMap().isEmpty()) { if (Files.exists(this.cacheFilePath)) { Files.delete(this.cacheFilePath); } From 2772c77247da7022539053e380beac8f2e1f6328 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Tue, 30 Sep 2025 12:20:49 +0800 Subject: [PATCH 096/125] =?UTF-8?q?feat(func):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BC=A4=E5=AE=B3=E7=8E=A9=E5=AE=B6=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/user/BukkitServerPlayer.java | 13 ++++- .../core/entity/player/Player.java | 2 + .../plugin/context/event/EventFunctions.java | 1 + .../context/function/CommonFunctions.java | 1 + .../context/function/DamageFunction.java | 51 +++++++++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageFunction.java 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 36ed88089..2b578908c 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 @@ -5,6 +5,8 @@ import com.google.common.collect.Lists; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.entity.BlockEntityHolder; @@ -45,6 +47,8 @@ import org.bukkit.*; import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeInstance; import org.bukkit.block.Block; +import org.bukkit.damage.DamageSource; +import org.bukkit.damage.DamageType; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.EquipmentSlot; @@ -506,7 +510,7 @@ public class BukkitServerPlayer extends Player { if (this.gameTicks % 20 == 0) { this.updateGUI(); } - if (this.isDestroyingBlock) { + if (this.isDestroyingBlock) { this.tickBlockDestroy(); } if (Config.predictBreaking() && !this.isDestroyingCustomBlock) { @@ -1133,4 +1137,11 @@ public class BukkitServerPlayer extends Player { Location location = new Location((org.bukkit.World) worldPosition.world().platformWorld(), worldPosition.x(), worldPosition.y(), worldPosition.z(), worldPosition.yRot(), worldPosition.xRot()); this.platformPlayer().teleportAsync(location, PlayerTeleportEvent.TeleportCause.PLUGIN); } + + @Override + public void damage(double amount, Key damageType) { + @SuppressWarnings("deprecation") + DamageType type = Registry.DAMAGE_TYPE.get(KeyUtils.toNamespacedKey(damageType)); + this.platformPlayer().damage(amount, DamageSource.builder(type != null ? type : DamageType.GENERIC).build()); + } } 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 6df8b25c7..f0da08202 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 @@ -169,4 +169,6 @@ public abstract class Player extends AbstractEntity implements NetWorkUser { public abstract CooldownData cooldown(); public abstract void teleport(WorldPosition worldPosition); + + public abstract void damage(double amount, Key damageType); } 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 8c36f5af6..e23bee3d9 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 @@ -45,6 +45,7 @@ public class EventFunctions { register(CommonFunctions.TELEPORT, new TeleportFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.SET_VARIABLE, new SetVariableFunction.FactoryImpl<>(EventConditions::fromMap)); register(CommonFunctions.TOAST, new ToastFunction.FactoryImpl<>(EventConditions::fromMap)); + register(CommonFunctions.DAMAGE, new DamageFunction.FactoryImpl<>(EventConditions::fromMap)); } public static void register(Key key, FunctionFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java index 143b02f1d..56c9ab931 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/CommonFunctions.java @@ -34,4 +34,5 @@ public final class CommonFunctions { public static final Key TELEPORT = Key.of("craftengine:teleport"); public static final Key TOAST = Key.of("craftengine:toast"); public static final Key SET_VARIABLE = Key.of("craftengine:set_variable"); + public static final Key DAMAGE = Key.of("craftengine:damage"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageFunction.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageFunction.java new file mode 100644 index 000000000..6ebb22d35 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/context/function/DamageFunction.java @@ -0,0 +1,51 @@ +package net.momirealms.craftengine.core.plugin.context.function; + +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.selector.PlayerSelector; +import net.momirealms.craftengine.core.plugin.context.selector.PlayerSelectors; +import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; + +import java.util.List; +import java.util.Map; + +public class DamageFunction extends AbstractConditionalFunction { + private final PlayerSelector selector; + private final Key damageType; + private final NumberProvider amount; + + public DamageFunction(PlayerSelector selector, Key damageType, NumberProvider amount, List> predicates) { + super(predicates); + this.selector = selector; + this.damageType = damageType; + this.amount = amount; + } + + @Override + protected void runInternal(CTX ctx) { + selector.get(ctx).forEach(p -> p.damage(amount.getDouble(ctx), damageType)); + } + + @Override + public Key type() { + return CommonFunctions.DAMAGE; + } + + public static class FactoryImpl extends AbstractFactory { + + public FactoryImpl(java.util.function.Function, Condition> factory) { + super(factory); + } + + @Override + public Function create(Map arguments) { + PlayerSelector selector = PlayerSelectors.fromObject(arguments.getOrDefault("target", "self"), conditionFactory()); + Key damageType = Key.of(ResourceConfigUtils.getAsString(arguments.getOrDefault("damage-type", "generic"))); + NumberProvider amount = NumberProviders.fromObject(arguments.getOrDefault("amount", 1f)); + return new DamageFunction<>(selector, damageType, amount, getPredicates(arguments)); + } + } +} From db07951974cb6be7538b42c1ea45649e6deaf98e Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Tue, 30 Sep 2025 18:27:58 +0800 Subject: [PATCH 097/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B7=B2=E7=9F=A5?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/DebugCleanCacheCommand.java | 210 ++++++++++-------- .../feature/DebugTargetBlockCommand.java | 9 +- .../core/item/AbstractItemManager.java | 25 ++- .../core/plugin/config/Config.java | 6 + gradle.properties | 2 +- 5 files changed, 141 insertions(+), 111 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java index 3c3ad6ed7..bf41e6f10 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java @@ -41,10 +41,10 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature @Override public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder - .required("type", StringParser.stringComponent().suggestionProvider(new SuggestionProvider<>() { + .optional("type", StringParser.stringComponent().suggestionProvider(new SuggestionProvider<>() { @Override public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(List.of(Suggestion.suggestion("custom-model-data"), Suggestion.suggestion("custom-block-states"), Suggestion.suggestion("visual-block-states"), Suggestion.suggestion("font"))); + return CompletableFuture.completedFuture(List.of(Suggestion.suggestion("custom-model-data"), Suggestion.suggestion("custom-block-states"), Suggestion.suggestion("visual-block-states"), Suggestion.suggestion("font"), Suggestion.suggestion("all"))); } })) .handler(context -> { @@ -52,103 +52,17 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature context.sender().sendMessage("The plugin is reloading. Please wait until the process is complete."); return; } - String type = context.get("type"); + String type = context.getOrDefault("type", "all"); switch (type) { - case "custom-model-data" -> { - BukkitItemManager instance = BukkitItemManager.instance(); - Map> idsMap = new HashMap<>(); - for (CustomItem item : instance.loadedItems().values()) { - Set ids = idsMap.computeIfAbsent(item.clientBoundMaterial(), k -> new HashSet<>()); - ids.add(item.id().asString()); - } - int total = 0; - for (Map.Entry entry : getAllCachedCustomModelData().entrySet()) { - Set ids = idsMap.getOrDefault(entry.getKey(), Collections.emptySet()); - List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); - total += removed.size(); - try { - entry.getValue().saveToCache(); - } catch (IOException e) { - this.plugin().logger().warn("Error while saving custom model data allocation for material " + entry.getKey().asString(), e); - return; - } - for (String id : removed) { - this.plugin().logger().info("Cleaned unsued item: " + id); - } - } - context.sender().sendMessage("Cleaned " + total + " unused custom model data"); - } - case "font", "images" -> { - BukkitFontManager instance = this.plugin().fontManager(); - Map> idsMap = new HashMap<>(); - for (BitmapImage image : instance.loadedImages().values()) { - Set ids = idsMap.computeIfAbsent(image.font(), k -> new HashSet<>()); - String id = image.id().toString(); - ids.add(id); - for (int i = 0; i < image.rows(); i++) { - for (int j = 0; j < image.columns(); j++) { - String imageArgs = id + ":" + i + ":" + j; - ids.add(imageArgs); - } - } - } - int total = 0; - for (Map.Entry entry : getAllCachedFont().entrySet()) { - Key font = entry.getKey(); - Set ids = idsMap.getOrDefault(font, Collections.emptySet()); - List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); - try { - entry.getValue().saveToCache(); - } catch (IOException e) { - this.plugin().logger().warn("Error while saving codepoint allocation for font " + font.asString(), e); - return; - } - for (String id : removed) { - this.plugin().logger().info("Cleaned unsued image: " + id); - } - total += removed.size(); - } - context.sender().sendMessage("Cleaned " + total + " unused codepoints"); - } - case "custom-block-states" -> { - BukkitBlockManager instance = BukkitBlockManager.instance(); - Set ids = new HashSet<>(); - for (CustomBlock customBlock : instance.loadedBlocks().values()) { - for (ImmutableBlockState state : customBlock.variantProvider().states()) { - ids.add(state.toString()); - } - } - IdAllocator idAllocator = instance.blockParser().internalIdAllocator(); - List removed = idAllocator.cleanupUnusedIds(i -> !ids.contains(i)); - try { - idAllocator.saveToCache(); - } catch (IOException e) { - this.plugin().logger().warn("Error while saving custom block states allocation", e); - } - for (String id : removed) { - this.plugin().logger().info("Cleaned unsued block state: " + id); - } - context.sender().sendMessage("Cleaned " + removed.size() + " unused custom block states"); - } - case "visual-block-states" -> { - BukkitBlockManager instance = BukkitBlockManager.instance(); - Set ids = new HashSet<>(); - for (CustomBlock customBlock : instance.loadedBlocks().values()) { - for (ImmutableBlockState state : customBlock.variantProvider().states()) { - ids.add(state.vanillaBlockState()); - } - } - VisualBlockStateAllocator visualBlockStateAllocator = instance.blockParser().visualBlockStateAllocator(); - List removed = visualBlockStateAllocator.cleanupUnusedIds(i -> !ids.contains(i)); - try { - visualBlockStateAllocator.saveToCache(); - } catch (IOException e) { - this.plugin().logger().warn("Error while saving visual block states allocation", e); - } - for (String id : removed) { - this.plugin().logger().info("Cleaned unsued block appearance: " + id); - } - context.sender().sendMessage("Cleaned " + removed.size() + " unused block state appearances"); + case "custom-model-data" -> handleCustomModelData(context); + case "font", "images" -> handleFont(context); + case "custom-block-states" -> handleCustomBlockState(context); + case "visual-block-states" -> handleVisualBlockState(context); + case "all" -> { + handleCustomModelData(context); + handleFont(context); + handleCustomBlockState(context); + handleVisualBlockState(context); } } }); @@ -159,6 +73,106 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature return "debug_clean_cache"; } + private void handleVisualBlockState(CommandContext context) { + BukkitBlockManager instance = BukkitBlockManager.instance(); + Set ids = new HashSet<>(); + for (CustomBlock customBlock : instance.loadedBlocks().values()) { + for (ImmutableBlockState state : customBlock.variantProvider().states()) { + ids.add(state.vanillaBlockState()); + } + } + VisualBlockStateAllocator visualBlockStateAllocator = instance.blockParser().visualBlockStateAllocator(); + List removed = visualBlockStateAllocator.cleanupUnusedIds(i -> !ids.contains(i)); + try { + visualBlockStateAllocator.saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving visual block states allocation", e); + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued block appearance: " + id); + } + context.sender().sendMessage("Cleaned " + removed.size() + " unused block state appearances"); + } + + private void handleCustomBlockState(CommandContext context) { + BukkitBlockManager instance = BukkitBlockManager.instance(); + Set ids = new HashSet<>(); + for (CustomBlock customBlock : instance.loadedBlocks().values()) { + for (ImmutableBlockState state : customBlock.variantProvider().states()) { + ids.add(state.toString()); + } + } + IdAllocator idAllocator = instance.blockParser().internalIdAllocator(); + List removed = idAllocator.cleanupUnusedIds(i -> !ids.contains(i)); + try { + idAllocator.saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving custom block states allocation", e); + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued block state: " + id); + } + context.sender().sendMessage("Cleaned " + removed.size() + " unused custom block states"); + } + + private void handleFont(CommandContext context) { + BukkitFontManager instance = this.plugin().fontManager(); + Map> idsMap = new HashMap<>(); + for (BitmapImage image : instance.loadedImages().values()) { + Set ids = idsMap.computeIfAbsent(image.font(), k -> new HashSet<>()); + String id = image.id().toString(); + ids.add(id); + for (int i = 0; i < image.rows(); i++) { + for (int j = 0; j < image.columns(); j++) { + String imageArgs = id + ":" + i + ":" + j; + ids.add(imageArgs); + } + } + } + int total = 0; + for (Map.Entry entry : getAllCachedFont().entrySet()) { + Key font = entry.getKey(); + Set ids = idsMap.getOrDefault(font, Collections.emptySet()); + List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); + try { + entry.getValue().saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving codepoint allocation for font " + font.asString(), e); + return; + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued image: " + id); + } + total += removed.size(); + } + context.sender().sendMessage("Cleaned " + total + " unused codepoints"); + } + + private void handleCustomModelData(CommandContext context) { + BukkitItemManager instance = BukkitItemManager.instance(); + Map> idsMap = new HashMap<>(); + for (CustomItem item : instance.loadedItems().values()) { + Set ids = idsMap.computeIfAbsent(item.clientBoundMaterial(), k -> new HashSet<>()); + ids.add(item.id().asString()); + } + int total = 0; + for (Map.Entry entry : getAllCachedCustomModelData().entrySet()) { + Set ids = idsMap.getOrDefault(entry.getKey(), Collections.emptySet()); + List removed = entry.getValue().cleanupUnusedIds(i -> !ids.contains(i)); + total += removed.size(); + try { + entry.getValue().saveToCache(); + } catch (IOException e) { + this.plugin().logger().warn("Error while saving custom model data allocation for material " + entry.getKey().asString(), e); + return; + } + for (String id : removed) { + this.plugin().logger().info("Cleaned unsued item: " + id); + } + } + context.sender().sendMessage("Cleaned " + total + " unused custom model data"); + } + public Map getAllCachedCustomModelData() { Path cacheDir = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("custom-model-data"); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java index 4ed380551..c684296a8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -10,6 +11,7 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.sender.Sender; +import net.momirealms.craftengine.core.plugin.config.Config; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; @@ -44,15 +46,14 @@ public class DebugTargetBlockCommand extends BukkitCommandFeature Sender sender = plugin().senderFactory().wrap(context.sender()); sender.sendMessage(Component.text(bData)); int id = BlockStateUtils.blockStateToId(blockState); - - Object holder = BukkitBlockManager.instance().getMinecraftBlockHolder(id); - if (holder != null) { + if (!BlockStateUtils.isVanillaBlock(id)) { + Object holder = BukkitBlockManager.instance().getMinecraftBlockHolder(id); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(id); if (immutableBlockState != null) { sender.sendMessage(Component.text(immutableBlockState.toString())); } ImmutableBlockState dataInCache = plugin().worldManager().getWorld(block.getWorld().getUID()).getBlockStateAtIfLoaded(LocationUtils.toBlockPos(block.getLocation())); - sender.sendMessage(Component.text("cache-state: " + !dataInCache.isEmpty())); + sender.sendMessage(Component.text("cache-state: " + (dataInCache != null && !dataInCache.isEmpty()))); try { @SuppressWarnings("unchecked") Set tags = (Set) CoreReflections.field$Holder$Reference$tags.get(holder); 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 9d3c7b909..7928753e7 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 @@ -338,7 +338,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } private boolean needsItemModelCompatibility() { - return Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2); + return Config.packMaxVersion().isAtOrAbove(MinecraftVersions.V1_21_2) && VersionHelper.isOrAbove1_21_2(); //todo 能否通过客户端包解决问题 } public Map idAllocators() { @@ -403,6 +403,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // custom model data CompletableFuture customModelDataFuture; + boolean forceCustomModelData; if (!isVanillaItem) { // 如果用户指定了,说明要手动分配,不管他是什么版本,都强制设置模型值 @@ -415,9 +416,11 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl throw new LocalizedResourceConfigException("warning.config.item.bad_custom_model_data", String.valueOf(customModelData)); } customModelDataFuture = getOrCreateIdAllocator(clientBoundMaterial).assignFixedId(id.asString(), customModelData); + forceCustomModelData = true; } // 用户没指定custom-model-data,则看当前资源包版本兼容需求 else { + forceCustomModelData = false; // 如果最低版本要1.21.1以下支持 if (needsCustomModelDataCompatibility()) { customModelDataFuture = getOrCreateIdAllocator(clientBoundMaterial).requestAutoId(id.asString()); @@ -428,6 +431,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } } else { + forceCustomModelData = false; // 原版物品不应该有这个 customModelDataFuture = CompletableFuture.completedFuture(0); } @@ -458,15 +462,17 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl // item model Key itemModel = null; + boolean forceItemModel = false; // 如果这个版本可以使用 item model if (!isVanillaItem && needsItemModelCompatibility()) { // 如果用户主动设定了item model,那么肯定要设置 if (section.containsKey("item-model")) { itemModel = Key.from(section.get("item-model").toString()); + forceItemModel = true; } // 用户没设置item model也没设置custom model data,那么为他生成一个基于物品id的item model - else if (customModelData == 0) { + else if (customModelData == 0 || Config.alwaysUseItemModel()) { itemModel = id; } // 用户没设置item model但是有custom model data,那么就使用custom model data @@ -476,11 +482,17 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl boolean clientBoundModel = VersionHelper.PREMIUM && (section.containsKey("client-bound-model") ? ResourceConfigUtils.getAsBoolean(section.get("client-bound-model"), "client-bound-model") : Config.globalClientboundModel()); CustomItem.Builder itemBuilder = createPlatformItemBuilder(uniqueId, material, clientBoundMaterial); - if (customModelData > 0) { + + // 模型配置区域,如果这里被配置了,那么用户必须要配置custom-model-data或item-model + Map modelSection = MiscUtils.castToMap(section.get("model"), true); + Map legacyModelSection = MiscUtils.castToMap(section.get("legacy-model"), true); + boolean hasModelSection = modelSection != null || legacyModelSection != null; + + if (customModelData > 0 && (hasModelSection || forceCustomModelData)) { if (clientBoundModel) itemBuilder.clientBoundDataModifier(new CustomModelDataModifier<>(customModelData)); else itemBuilder.dataModifier(new CustomModelDataModifier<>(customModelData)); } - if (itemModel != null) { + if (itemModel != null && (hasModelSection || forceItemModel)) { if (clientBoundModel) itemBuilder.clientBoundDataModifier(new ItemModelModifier<>(itemModel)); else itemBuilder.dataModifier(new ItemModelModifier<>(itemModel)); } @@ -586,10 +598,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl return; } - // 模型配置区域,如果这里被配置了,那么用户必须要配置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) { + if (!hasModelSection) { collector.throwIfPresent(); return; } 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 357414f9a..788862341 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 @@ -164,6 +164,7 @@ public class Config { protected boolean item$update_triggers$pick_up; protected int item$custom_model_data_starting_value$default; protected Map item$custom_model_data_starting_value$overrides; + protected boolean item$always_use_item_model; protected String equipment$sacrificed_vanilla_armor$type; protected Key equipment$sacrificed_vanilla_armor$asset_id; @@ -407,6 +408,7 @@ public class Config { item$update_triggers$drop = config.getBoolean("item.update-triggers.drop", false); item$update_triggers$pick_up = config.getBoolean("item.update-triggers.pick-up", false); item$custom_model_data_starting_value$default = config.getInt("item.custom-model-data-starting-value.default", 10000); + item$always_use_item_model = config.getBoolean("item.always-use-item-model", true) && VersionHelper.isOrAbove1_21_2(); Section customModelDataOverridesSection = config.getSection("item.custom-model-data-starting-value.overrides"); if (customModelDataOverridesSection != null) { @@ -549,6 +551,10 @@ public class Config { return instance.block$serverside_blocks; } + public static boolean alwaysUseItemModel() { + return instance.item$always_use_item_model; + } + public static boolean filterConfigurationPhaseDisconnect() { return instance.filterConfigurationPhaseDisconnect; } diff --git a/gradle.properties b/gradle.properties index 1de766a2f..f633a3e61 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.8 +project_version=0.0.63.9 config_version=47 lang_version=32 project_group=net.momirealms From be830b8b7acb848dfd7ef5fe08db603a6b2a3d30 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Thu, 2 Oct 2025 02:48:19 +0800 Subject: [PATCH 098/125] =?UTF-8?q?=E6=94=B9=E8=BF=9Bs3=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common-files/src/main/resources/translations/en.yml | 4 ++++ common-files/src/main/resources/translations/zh_cn.yml | 4 ++++ core/build.gradle.kts | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 2c0551596..745d94e46 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -386,10 +386,14 @@ warning.config.host.onedrive.missing_client_secret: "Issue found in conf warning.config.host.onedrive.missing_refresh_token: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'refresh-token' argument or environment variable 'CE_ONEDRIVE_REFRESH_TOKEN' for onedrive host." warning.config.host.onedrive.missing_upload_path: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'upload-path' argument for onedrive host." warning.config.host.s3.missing_endpoint: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'endpoint' argument for s3 host." +warning.config.host.s3.missing_protocol: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'protocol' argument for s3 host." warning.config.host.s3.missing_bucket: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'bucket' argument for s3 host." +warning.config.host.s3.missing_region: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'region' argument for s3 host." warning.config.host.s3.missing_access_key: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'access-key-id' argument or environment variable 'CE_S3_ACCESS_KEY_ID' for s3 host." warning.config.host.s3.missing_secret: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'access-key-secret' argument or environment variable 'CE_S3_ACCESS_KEY_SECRET' for s3 host." warning.config.host.s3.missing_upload_path: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'upload-path' argument for s3 host." +warning.config.host.s3.missing_cdn_domain: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'cdn.domain' argument for s3 host." +warning.config.host.s3.missing_cdn_protocol: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'cdn.protocol' argument for s3 host." warning.config.host.self.missing_ip: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Missing required 'ip' argument for self host." warning.config.host.self.invalid_port: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Invalid port '' for self host." warning.config.host.self.invalid_url: "Issue found in config.yml at 'resource-pack.delivery.hosting' - Invalid url '' for self host." diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 97c6d2d43..5549ef095 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -372,10 +372,14 @@ warning.config.host.onedrive.missing_client_secret: "在 config.yml 的 warning.config.host.onedrive.missing_refresh_token: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - OneDrive 托管缺少必需的 'refresh-token' 参数或环境变量 'CE_ONEDRIVE_REFRESH_TOKEN'" warning.config.host.onedrive.missing_upload_path: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - OneDrive 托管缺少必需的 'upload-path' 参数" warning.config.host.s3.missing_endpoint: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'endpoint' 参数" +warning.config.host.s3.missing_protocol: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'protocol' 参数" warning.config.host.s3.missing_bucket: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'bucket' 参数" +warning.config.host.s3.missing_region: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'region' 参数" warning.config.host.s3.missing_access_key: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'access-key-id' 参数或环境变量 'CE_S3_ACCESS_KEY_ID'" warning.config.host.s3.missing_secret: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'access-key-secret' 参数或环境变量 'CE_S3_ACCESS_KEY_SECRET'" warning.config.host.s3.missing_upload_path: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'upload-path' 参数" +warning.config.host.s3.missing_cdn_domain: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'cdn.domain' 参数" +warning.config.host.s3.missing_cdn_protocol: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - S3 托管缺少必需的 'cdn.protocol' 参数" warning.config.host.self.missing_ip: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管缺少必需的 'ip' 参数" warning.config.host.self.invalid_port: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管的端口 '' 无效" warning.config.host.self.invalid_url: "在 config.yml 的 'resource-pack.delivery.hosting' 处发现问题 - 自托管托管的 URL '' 无效" diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 352ad960b..58d4ada3e 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -21,7 +21,7 @@ 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.5") + implementation("net.momirealms:craft-engine-s3:0.6") // Util compileOnly("net.momirealms:sparrow-util:${rootProject.properties["sparrow_util_version"]}") // Adventure From ed26d25c318da6728f6e6da66aca1c6469cc8c38 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Thu, 2 Oct 2025 03:21:26 +0800 Subject: [PATCH 099/125] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=B8=80=E7=82=B9?= =?UTF-8?q?=E4=B8=9C=E8=A5=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index f633a3e61..eb221bd28 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,13 +6,13 @@ project_version=0.0.63.9 config_version=47 lang_version=32 project_group=net.momirealms -latest_supported_version=1.21.8 +latest_supported_version=1.21.9 # Supported languages supported_languages=en,zh_cn,zh_tw,es,tr,de,ru_ru # Dependency settings -paper_version=1.21.8 +paper_version=1.21.9 jetbrains_annotations_version=26.0.2 slf4j_version=2.0.17 log4j_version=2.25.2 From be5edc66ce465ac854192d0f3a5462e6aecac6f6 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Thu, 2 Oct 2025 04:22:36 +0800 Subject: [PATCH 100/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E5=B0=8F=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/command/BukkitCommandManager.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) 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 14c4d9378..2babb4c6c 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 @@ -6,6 +6,8 @@ import net.momirealms.craftengine.bukkit.plugin.command.feature.*; import net.momirealms.craftengine.core.plugin.command.AbstractCommandManager; import net.momirealms.craftengine.core.plugin.command.CommandFeature; import net.momirealms.craftengine.core.plugin.command.sender.Sender; +import net.momirealms.craftengine.core.util.ReflectionUtils; +import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.command.CommandSender; import org.incendo.cloud.SenderMapper; import org.incendo.cloud.bukkit.CloudBukkitCapabilities; @@ -24,7 +26,11 @@ public class BukkitCommandManager extends AbstractCommandManager plugin.javaPlugin(), ExecutionCoordinator.simpleCoordinator(), SenderMapper.identity() - )); + ) {{ // TODO:等 cloud 修复后移除,绕过 obc.command.BukkitCommandWrapper 类检查,因为这个类在 1.21.9 版本被移除了,并且项目貌似没用到这个 + if (VersionHelper.isOrAbove1_21_9() && ReflectionUtils.classExists("com.mojang.brigadier.tree.CommandNode")) { + registerCapability(CloudBukkitCapabilities.BRIGADIER); + } + }}); this.plugin = plugin; this.index = Index.create(CommandFeature::getFeatureID, List.of( new ReloadCommand(this, plugin), @@ -61,7 +67,7 @@ public class BukkitCommandManager extends AbstractCommandManager )); final LegacyPaperCommandManager manager = (LegacyPaperCommandManager) getCommandManager(); manager.settings().set(ManagerSetting.ALLOW_UNSAFE_REGISTRATION, true); - if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER) && manager.hasCapability(CloudBukkitCapabilities.BRIGADIER)) { + if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) { manager.registerBrigadier(); manager.brigadierManager().setNativeNumberSuggestions(true); } else if (manager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) { From 6891792463f4e6d4313002fbc0a800256357d51b Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Thu, 2 Oct 2025 22:17:36 +0800 Subject: [PATCH 101/125] =?UTF-8?q?=E5=88=9D=E6=AD=A51.21.10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/bukkit/item/factory/BukkitItemFactory.java | 2 +- .../momirealms/craftengine/core/util/MinecraftVersion.java | 1 + .../momirealms/craftengine/core/util/MinecraftVersions.java | 1 + .../net/momirealms/craftengine/core/util/VersionHelper.java | 6 ++++++ gradle.properties | 2 +- 5 files changed, 10 insertions(+), 2 deletions(-) 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 f836d910b..d37bf367b 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 @@ -49,7 +49,7 @@ public abstract class BukkitItemFactory> extend case "1.21.4" -> { return new ComponentItemFactory1_21_4(plugin); } - case "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9" -> { + case "1.21.5", "1.21.6", "1.21.7", "1.21.8", "1.21.9", "1.21.10" -> { return new ComponentItemFactory1_21_5(plugin); } default -> throw new IllegalStateException("Unsupported server version: " + plugin.serverVersion()); 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 80fc10b38..ce62c8b2f 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 @@ -23,6 +23,7 @@ public final class MinecraftVersion implements Comparable { PACK_FORMATS.put(1_21_07, 64); PACK_FORMATS.put(1_21_08, 64); PACK_FORMATS.put(1_21_09, 69); + PACK_FORMATS.put(1_21_10, 69); 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 b9c6980cc..d97303302 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 @@ -20,5 +20,6 @@ public final class MinecraftVersions { public static final MinecraftVersion V1_21_7 = new MinecraftVersion("1.21.7"); public static final MinecraftVersion V1_21_8 = new MinecraftVersion("1.21.8"); public static final MinecraftVersion V1_21_9 = new MinecraftVersion("1.21.9"); + public static final MinecraftVersion V1_21_10 = new MinecraftVersion("1.21.10"); public static final MinecraftVersion FUTURE = new MinecraftVersion("1.99.99"); } 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 2112ecd15..b0b7a6031 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 @@ -34,6 +34,7 @@ public class VersionHelper { private static final boolean v1_21_7; private static final boolean v1_21_8; private static final boolean v1_21_9; + private static final boolean v1_21_10; static { try (InputStream inputStream = Class.forName("net.minecraft.obfuscate.DontObfuscate").getResourceAsStream("/version.json")) { @@ -70,6 +71,7 @@ public class VersionHelper { v1_21_7 = version >= 12107; v1_21_8 = version >= 12108; v1_21_9 = version >= 12109; + v1_21_10 = version >= 12110; majorVersion = major; minorVersion = minor; @@ -245,4 +247,8 @@ public class VersionHelper { public static boolean isOrAbove1_21_9() { return v1_21_9; } + + public static boolean isOrAbove1_21_10() { + return v1_21_10; + } } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index eb221bd28..8d69cac36 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ project_version=0.0.63.9 config_version=47 lang_version=32 project_group=net.momirealms -latest_supported_version=1.21.9 +latest_supported_version=1.21.10 # Supported languages supported_languages=en,zh_cn,zh_tw,es,tr,de,ru_ru From edf6b8940cf5c5bf52204e3fb1bbd6038854b107 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Thu, 2 Oct 2025 23:39:13 +0800 Subject: [PATCH 102/125] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=89=A9=E5=93=81?= =?UTF-8?q?=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/item/BukkitItemManager.java | 2 + .../plugin/command/BukkitCommandManager.java | 1 + .../feature/DebugTargetBlockCommand.java | 2 - .../command/feature/GetItemCommand.java | 26 +-- .../command/feature/GiveItemCommand.java | 36 +--- .../command/feature/OverrideGiveCommand.java | 91 ++++++++++ .../feature/SearchRecipeAdminCommand.java | 2 +- .../feature/SearchUsageAdminCommand.java | 2 +- .../plugin/user/BukkitServerPlayer.java | 5 +- .../craftengine/bukkit/util/PlayerUtils.java | 155 ++++-------------- .../core/item/AbstractItemManager.java | 24 ++- .../craftengine/core/item/ItemManager.java | 4 +- gradle.properties | 2 +- 13 files changed, 165 insertions(+), 187 deletions(-) create mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/OverrideGiveCommand.java 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 2318e20a9..9fceb0e68 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 @@ -27,6 +27,7 @@ import net.momirealms.craftengine.core.util.*; import org.bukkit.Bukkit; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; +import org.incendo.cloud.suggestion.Suggestion; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -402,6 +403,7 @@ public class BukkitItemManager extends AbstractItemManager { Object resourceLocation = FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, item); Key itemKey = KeyUtils.resourceLocationToKey(resourceLocation); VANILLA_ITEMS.add(itemKey); + super.cachedVanillaItemSuggestions.add(Suggestion.suggestion(itemKey.asString())); 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); 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 2babb4c6c..e39eca2f5 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 @@ -64,6 +64,7 @@ public class BukkitCommandManager extends AbstractCommandManager new SendResourcePackCommand(this, plugin), new DebugSaveDefaultResourcesCommand(this, plugin), new DebugCleanCacheCommand(this, plugin) +// new OverrideGiveCommand(this, plugin) )); final LegacyPaperCommandManager manager = (LegacyPaperCommandManager) getCommandManager(); manager.settings().set(ManagerSetting.ALLOW_UNSAFE_REGISTRATION, true); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java index c684296a8..7535abf8d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java @@ -2,7 +2,6 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -11,7 +10,6 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.sender.Sender; -import net.momirealms.craftengine.core.plugin.config.Config; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java index 4c9143aab..9326accf6 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java @@ -1,11 +1,13 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.util.PlayerUtils; import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.FlagKeys; @@ -37,18 +39,16 @@ public class GetItemCommand extends BukkitCommandFeature { return builder .senderType(Player.class) .flag(FlagKeys.SILENT_FLAG) - .flag(FlagKeys.TO_INVENTORY_FLAG) .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { @Override public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions()); + return CompletableFuture.completedFuture(plugin().itemManager().cachedCustomItemSuggestions()); } })) - .optional("amount", IntegerParser.integerParser(1, 6400)) + .optional("amount", IntegerParser.integerParser(1, 9999)) .handler(context -> { Player player = context.sender(); int amount = context.getOrDefault("amount", 1); - boolean toInv = context.flags().hasFlag(FlagKeys.TO_INVENTORY); NamespacedKey namespacedKey = context.get("id"); Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value()); CustomItem customItem = CraftEngineItems.byId(itemId); @@ -61,24 +61,16 @@ public class GetItemCommand extends BukkitCommandFeature { itemId = customItem.id(); } } - ItemStack builtItem = customItem.buildItemStack(plugin().adapt(context.sender())); - int amountToGive = amount; - int maxStack = builtItem.getMaxStackSize(); - while (amountToGive > 0) { - int perStackSize = Math.min(maxStack, amountToGive); - amountToGive -= perStackSize; - ItemStack more = builtItem.clone(); - more.setAmount(perStackSize); - if (toInv) { - PlayerUtils.putItemsToInventory(player.getInventory(), more, more.getAmount()); - } else { - PlayerUtils.dropItem(player, more, false, true, false); - } + Item builtItem = customItem.buildItem(BukkitAdaptors.adapt(player)); + if (builtItem != null) { + PlayerUtils.giveItem(player, amount, builtItem); } handleFeedback(context, MessageConstants.COMMAND_ITEM_GET_SUCCESS, Component.text(amount), Component.text(itemId.toString())); }); } + + @Override public String getFeatureID() { return "get_item"; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java index 6f546d394..cd66ee42a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java @@ -1,17 +1,18 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.util.PlayerUtils; import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.FlagKeys; import net.momirealms.craftengine.core.plugin.locale.MessageConstants; import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.NamespacedKey; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -40,19 +41,17 @@ public class GiveItemCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder .flag(FlagKeys.SILENT_FLAG) - .flag(FlagKeys.TO_INVENTORY_FLAG) .required("player", MultiplePlayerSelectorParser.multiplePlayerSelectorParser(true)) .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { @Override public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions()); + return CompletableFuture.completedFuture(plugin().itemManager().cachedCustomItemSuggestions()); } })) - .optional("amount", IntegerParser.integerParser(1, 6400)) + .optional("amount", IntegerParser.integerParser(1, 9999)) .handler(context -> { MultiplePlayerSelector selector = context.get("player"); int amount = context.getOrDefault("amount", 1); - boolean toInv = context.flags().hasFlag(FlagKeys.TO_INVENTORY); NamespacedKey namespacedKey = context.get("id"); Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value()); CustomItem customItem = CraftEngineItems.byId(itemId); @@ -67,30 +66,9 @@ public class GiveItemCommand extends BukkitCommandFeature { } Collection players = selector.values(); for (Player player : players) { - ItemStack builtItem = customItem.buildItemStack(plugin().adapt(player)); - if (builtItem == null) { - return; - } - int amountToGive = amount; - int maxStack = builtItem.getMaxStackSize(); - while (amountToGive > 0) { - int perStackSize = Math.min(maxStack, amountToGive); - amountToGive -= perStackSize; - ItemStack more = builtItem.clone(); - more.setAmount(perStackSize); - if (toInv) { - if (VersionHelper.isFolia()) { - player.getScheduler().run(plugin().javaPlugin(), (t) -> PlayerUtils.putItemsToInventory(player.getInventory(), more, more.getAmount()), () -> {}); - } else { - PlayerUtils.putItemsToInventory(player.getInventory(), more, more.getAmount()); - } - } else { - if (VersionHelper.isFolia()) { - player.getScheduler().run(plugin().javaPlugin(), (t) -> PlayerUtils.dropItem(player, more, false, true, false), () -> {}); - } else { - PlayerUtils.dropItem(player, more, false, true, false); - } - } + Item builtItem = customItem.buildItem(BukkitAdaptors.adapt(player)); + if (builtItem != null) { + PlayerUtils.giveItem(player, amount, builtItem); } } if (players.size() == 1) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/OverrideGiveCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/OverrideGiveCommand.java new file mode 100644 index 000000000..4fbf77a78 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/OverrideGiveCommand.java @@ -0,0 +1,91 @@ +//package net.momirealms.craftengine.bukkit.plugin.command.feature; +// +//import net.kyori.adventure.text.Component; +//import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; +//import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +//import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +//import net.momirealms.craftengine.bukkit.util.PlayerUtils; +//import net.momirealms.craftengine.core.item.Item; +//import net.momirealms.craftengine.core.plugin.CraftEngine; +//import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; +//import net.momirealms.craftengine.core.plugin.locale.MessageConstants; +//import net.momirealms.craftengine.core.util.Key; +//import org.bukkit.NamespacedKey; +//import org.bukkit.command.CommandSender; +//import org.bukkit.entity.Player; +//import org.bukkit.inventory.ItemStack; +//import org.checkerframework.checker.nullness.qual.NonNull; +//import org.incendo.cloud.Command; +//import org.incendo.cloud.bukkit.data.MultiplePlayerSelector; +//import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; +//import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser; +//import org.incendo.cloud.context.CommandContext; +//import org.incendo.cloud.context.CommandInput; +//import org.incendo.cloud.parser.standard.IntegerParser; +//import org.incendo.cloud.suggestion.Suggestion; +//import org.incendo.cloud.suggestion.SuggestionProvider; +// +//import java.util.Collection; +//import java.util.concurrent.CompletableFuture; +// +//public class OverrideGiveCommand extends BukkitCommandFeature { +// +// public OverrideGiveCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { +// super(commandManager, plugin); +// } +// +// @Override +// public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { +// return builder +// .required("player", MultiplePlayerSelectorParser.multiplePlayerSelectorParser(true)) +// .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { +// @Override +// public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { +// return CompletableFuture.completedFuture(plugin().itemManager().cachedAllItemSuggestions()); +// } +// })) +// .optional("amount", IntegerParser.integerParser(1, 6400)) +// .handler(context -> { +// MultiplePlayerSelector selector = context.get("player"); +// int amount = context.getOrDefault("amount", 1); +// NamespacedKey namespacedKey = context.get("id"); +// Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value()); +// Collection players = selector.values(); +// +// Component anyItemDisplayName = null; +// +// for (Player player : players) { +// Item builtItem = BukkitItemManager.instance().createWrappedItem(itemId, BukkitAdaptors.adapt(player)); +// if (builtItem == null) { +// return; +// } +// int maxStack = builtItem.maxStackSize(); +// anyItemDisplayName = builtItem.hoverNameComponent() +// .orElseGet(() -> { +// if (builtItem.isCustomItem()) { +// return Component.text(itemId.asString()); +// } else { +// return Component.translatable("item.minecraft." + itemId.value()); +// } +// }); +// +// if (amount > maxStack * 100) { +// plugin().senderFactory().wrap(context.sender()).sendMessage(Component.translatable("commands.give.failed.toomanyitems", Component.text(maxStack * 100), anyItemDisplayName); +// return; +// } +// +// PlayerUtils.giveItem(player, amount, builtItem); +// } +// if (players.size() == 1) { +// plugin().senderFactory().wrap(context.sender()).sendMessage(Component.translatable("commands.give.success.single", Component.text(amount), anyItemDisplayName, )); +// } else if (players.size() > 1) { +// handleFeedback(context, MessageConstants.COMMAND_ITEM_GIVE_SUCCESS_MULTIPLE, Component.text(amount), Component.text(itemId.toString()), Component.text(players.size())); +// } +// }); +// } +// +// @Override +// public String getFeatureID() { +// return "override_minecraft_give"; +// } +//} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java index c5c7847f5..254a40037 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchRecipeAdminCommand.java @@ -37,7 +37,7 @@ public class SearchRecipeAdminCommand extends BukkitCommandFeature() { @Override public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions()); + return CompletableFuture.completedFuture(plugin().itemManager().cachedCustomItemSuggestions()); } })) .handler(context -> { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java index 034be222d..ee5b93bde 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/SearchUsageAdminCommand.java @@ -37,7 +37,7 @@ public class SearchUsageAdminCommand extends BukkitCommandFeature .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { @Override public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { - return CompletableFuture.completedFuture(plugin().itemManager().cachedSuggestions()); + return CompletableFuture.completedFuture(plugin().itemManager().cachedCustomItemSuggestions()); } })) .handler(context -> { 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 2b578908c..41aae4987 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 @@ -5,8 +5,6 @@ import com.google.common.collect.Lists; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; -import io.papermc.paper.registry.RegistryAccess; -import io.papermc.paper.registry.RegistryKey; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.entity.BlockEntityHolder; @@ -378,9 +376,10 @@ public class BukkitServerPlayer extends Player { platformPlayer().playSound(new Location(null, pos.x(), pos.y(), pos.z()), sound.toString(), SoundUtils.toBukkit(source), volume, pitch); } + @SuppressWarnings("unchecked") @Override public void giveItem(Item item) { - PlayerUtils.giveItem(platformPlayer(), (ItemStack) item.getItem(), item.count()); + PlayerUtils.giveItem(platformPlayer(), item.count(), (Item) item); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java index 9a0c33285..ae2a6a2b3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java @@ -7,148 +7,49 @@ import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.util.RandomUtils; -import org.bukkit.Location; -import org.bukkit.entity.Item; +import net.momirealms.craftengine.core.util.VersionHelper; +import org.bukkit.Sound; +import org.bukkit.SoundCategory; import org.bukkit.entity.Player; -import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.util.Vector; -import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; -import static java.util.Objects.requireNonNull; - public final class PlayerUtils { private PlayerUtils() { } - public static void dropItem(@NotNull Player player, @NotNull ItemStack itemStack, boolean retainOwnership, boolean noPickUpDelay, boolean throwRandomly) { - requireNonNull(player, "player"); - requireNonNull(itemStack, "itemStack"); - Location location = player.getLocation().clone(); - Item item = player.getWorld().dropItem(player.getEyeLocation().clone().subtract(new Vector(0, 0.3, 0)), itemStack); - item.setPickupDelay(noPickUpDelay ? 0 : 40); - item.setOwner(player.getUniqueId()); - if (retainOwnership) { - item.setThrower(player.getUniqueId()); + public static void giveItem(Player player, int amount, Item original) { + int amountToGive = amount; + int maxStack = original.maxStackSize(); + while (amountToGive > 0) { + int perStackSize = Math.min(maxStack, amountToGive); + amountToGive -= perStackSize; + PlayerUtils.giveItem(player, original, original.copyWithCount(perStackSize)); } - if (throwRandomly) { - double d1 = RandomUtils.generateRandomDouble(0, 1) * 0.5f; - double d2 = RandomUtils.generateRandomDouble(0, 1) * (Math.PI * 2); - item.setVelocity(new Vector(-Math.sin(d2) * d1, 0.2f, Math.cos(d2) * d1)); + } + + public static void giveItem(Player player, Item original, Item item) { + Object serverPlayer = FastNMS.INSTANCE.method$CraftPlayer$getHandle(player); + Object inventory = FastNMS.INSTANCE.method$Player$getInventory(serverPlayer); + boolean flag = FastNMS.INSTANCE.method$Inventory$add(inventory, item.getLiteralObject()); + if (flag && item.isEmpty()) { + Object droppedItem = FastNMS.INSTANCE.method$ServerPlayer$drop(serverPlayer, original.copyWithCount(1).getLiteralObject(), false, false, false, null); + if (droppedItem != null) { + FastNMS.INSTANCE.method$ItemEntity$makeFakeItem(droppedItem); + } + player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 0.2F, ((RandomUtils.generateRandomFloat(0, 1) - RandomUtils.generateRandomFloat(0, 1)) * 0.7F + 1.0F) * 2.0F); + FastNMS.INSTANCE.method$AbstractContainerMenu$broadcastChanges(FastNMS.INSTANCE.field$Player$containerMenu(serverPlayer)); } else { - double d1 = Math.sin(location.getPitch() * (Math.PI / 180)); - double d2 = RandomUtils.generateRandomDouble(0, 0.02); - double d3 = RandomUtils.generateRandomDouble(0, 1) * (Math.PI * 2); - Vector vector = location.getDirection().multiply(0.3).setY(-d1 * 0.3 + 0.1 + (RandomUtils.generateRandomDouble(0, 1) - RandomUtils.generateRandomDouble(0, 1)) * 0.1); - vector.add(new Vector(Math.cos(d3) * d2, 0, Math.sin(d3) * d2)); - item.setVelocity(vector); - } - } - - public static int putItemsToInventory(Inventory inventory, ItemStack itemStack, int amount) { - ItemMeta meta = itemStack.getItemMeta(); - int maxStackSize = itemStack.getMaxStackSize(); - for (ItemStack other : inventory.getStorageContents()) { - if (other != null) { - if (other.getType() == itemStack.getType() && other.getItemMeta().equals(meta)) { - if (other.getAmount() < maxStackSize) { - int delta = maxStackSize - other.getAmount(); - if (amount > delta) { - other.setAmount(maxStackSize); - amount -= delta; - } else { - other.setAmount(amount + other.getAmount()); - return 0; - } - } - } + Object droppedItem = FastNMS.INSTANCE.method$ServerPlayer$drop(serverPlayer, item.getLiteralObject(), false, false, !VersionHelper.isOrAbove1_21_5(), null); + if (droppedItem != null) { + FastNMS.INSTANCE.method$ItemEntity$setNoPickUpDelay(droppedItem); + FastNMS.INSTANCE.method$ItemEntity$setTarget(droppedItem, player.getUniqueId()); } } - - if (amount > 0) { - for (ItemStack other : inventory.getStorageContents()) { - if (other == null) { - if (amount > maxStackSize) { - amount -= maxStackSize; - ItemStack cloned = itemStack.clone(); - cloned.setAmount(maxStackSize); - inventory.addItem(cloned); - } else { - ItemStack cloned = itemStack.clone(); - cloned.setAmount(amount); - inventory.addItem(cloned); - return 0; - } - } - } - } - - return amount; - } - - public static int giveItem(Player player, ItemStack itemStack, int amount) { - PlayerInventory inventory = player.getInventory(); - ItemMeta meta = itemStack.getItemMeta(); - int maxStackSize = itemStack.getMaxStackSize(); - if (amount > maxStackSize * 100) { - amount = maxStackSize * 100; - } - int actualAmount = amount; - for (ItemStack other : inventory.getStorageContents()) { - if (other != null) { - if (other.getType() == itemStack.getType() && other.getItemMeta().equals(meta)) { - if (other.getAmount() < maxStackSize) { - int delta = maxStackSize - other.getAmount(); - if (amount > delta) { - other.setAmount(maxStackSize); - amount -= delta; - } else { - other.setAmount(amount + other.getAmount()); - return actualAmount; - } - } - } - } - } - if (amount > 0) { - for (ItemStack other : inventory.getStorageContents()) { - if (other == null) { - if (amount > maxStackSize) { - amount -= maxStackSize; - ItemStack cloned = itemStack.clone(); - cloned.setAmount(maxStackSize); - inventory.addItem(cloned); - } else { - ItemStack cloned = itemStack.clone(); - cloned.setAmount(amount); - inventory.addItem(cloned); - return actualAmount; - } - } - } - } - - if (amount > 0) { - for (int i = 0; i < amount / maxStackSize; i++) { - ItemStack cloned = itemStack.clone(); - cloned.setAmount(maxStackSize); - player.getWorld().dropItem(player.getLocation(), cloned); - } - int left = amount % maxStackSize; - if (left != 0) { - ItemStack cloned = itemStack.clone(); - cloned.setAmount(left); - player.getWorld().dropItem(player.getLocation(), cloned); - } - } - - return actualAmount; } public static void sendTotemAnimation(Player player, ItemStack totem) { 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 7928753e7..7f95e173a 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 @@ -59,7 +59,9 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl protected final Map> modernOverrides = new HashMap<>(); protected final Map equipments = new HashMap<>(); // Cached command suggestions - protected final List cachedSuggestions = new ArrayList<>(); + protected final List cachedCustomItemSuggestions = new ArrayList<>(); + protected final List cachedAllItemSuggestions = new ArrayList<>(); + protected final List cachedVanillaItemSuggestions = new ArrayList<>(); protected final List cachedTotemSuggestions = new ArrayList<>(); protected AbstractItemManager(CraftEngine plugin) { @@ -130,7 +132,8 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl super.clearModelsToGenerate(); this.customItemsById.clear(); this.customItemsByPath.clear(); - this.cachedSuggestions.clear(); + this.cachedCustomItemSuggestions.clear(); + this.cachedAllItemSuggestions.clear(); this.cachedTotemSuggestions.clear(); this.legacyOverrides.clear(); this.modernOverrides.clear(); @@ -181,7 +184,7 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl this.customItemsByPath.put(id.value(), customItem); if (!customItem.isVanillaItem()) { // cache command suggestions - this.cachedSuggestions.add(Suggestion.suggestion(id.toString())); + this.cachedCustomItemSuggestions.add(Suggestion.suggestion(id.toString())); // totem animations if (VersionHelper.isOrAbove1_21_2()) { this.cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); @@ -208,8 +211,13 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } @Override - public Collection cachedSuggestions() { - return Collections.unmodifiableCollection(this.cachedSuggestions); + public Collection cachedCustomItemSuggestions() { + return Collections.unmodifiableCollection(this.cachedCustomItemSuggestions); + } + + @Override + public Collection cachedAllItemSuggestions() { + return Collections.unmodifiableCollection(this.cachedAllItemSuggestions); } @Override @@ -239,6 +247,12 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl } } + @Override + public void delayedLoad() { + this.cachedAllItemSuggestions.addAll(this.cachedVanillaItemSuggestions); + this.cachedAllItemSuggestions.addAll(this.cachedCustomItemSuggestions); + } + @Override public Map> loadedItems() { return Collections.unmodifiableMap(this.customItemsById); 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 a255c23de..e837c541d 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 @@ -102,7 +102,9 @@ public interface ItemManager extends Manageable, ModelGenerator { int fuelTime(Key id); - Collection cachedSuggestions(); + Collection cachedCustomItemSuggestions(); + + Collection cachedAllItemSuggestions(); Collection cachedTotemSuggestions(); diff --git a/gradle.properties b/gradle.properties index 8d69cac36..f50bd8c61 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.98 +nms_helper_version=1.0.100 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5 From f662820f5eb5146dfb21e35efa26c119d43508f3 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 3 Oct 2025 03:01:05 +0800 Subject: [PATCH 103/125] =?UTF-8?q?=E6=94=B9=E8=BF=9B3=E4=B8=AA=E8=B0=83?= =?UTF-8?q?=E8=AF=95=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/DebugGetBlockInternalIdCommand.java | 10 +++++++++- .../DebugGetBlockStateRegistryIdCommand.java | 11 ++++++++--- .../command/feature/DebugTargetBlockCommand.java | 13 +++++++++---- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugGetBlockInternalIdCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugGetBlockInternalIdCommand.java index f08c257c0..66072947f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugGetBlockInternalIdCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugGetBlockInternalIdCommand.java @@ -1,5 +1,8 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.ImmutableBlockState; @@ -7,6 +10,7 @@ import net.momirealms.craftengine.core.block.parser.BlockStateParser; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.FlagKeys; +import net.momirealms.craftengine.core.plugin.command.sender.Sender; import org.bukkit.command.CommandSender; import org.checkerframework.checker.nullness.qual.NonNull; import org.incendo.cloud.Command; @@ -38,7 +42,11 @@ public class DebugGetBlockInternalIdCommand extends BukkitCommandFeature assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { return builder - .senderType(Player.class) .required("state", StringParser.greedyStringParser()) .handler(context -> { String state = context.get("state"); BlockData blockData = Bukkit.createBlockData(state); int id = BlockStateUtils.blockDataToId(blockData); - context.sender().sendMessage(String.valueOf(id)); + Sender sender = plugin().senderFactory().wrap(context.sender()); + sender.sendMessage(Component.text(id) + .hoverEvent(Component.text("Copy", NamedTextColor.YELLOW)) + .clickEvent(ClickEvent.suggestCommand(String.valueOf(id)))); }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java index c684296a8..9a9f344d1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugTargetBlockCommand.java @@ -1,8 +1,9 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.ClickEvent; +import net.kyori.adventure.text.format.NamedTextColor; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; @@ -11,7 +12,6 @@ import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.sender.Sender; -import net.momirealms.craftengine.core.plugin.config.Config; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.command.CommandSender; @@ -44,13 +44,18 @@ public class DebugTargetBlockCommand extends BukkitCommandFeature String bData = block.getBlockData().getAsString(); Object blockState = BlockStateUtils.blockDataToBlockState(block.getBlockData()); Sender sender = plugin().senderFactory().wrap(context.sender()); - sender.sendMessage(Component.text(bData)); + sender.sendMessage(Component.text(bData) + .hoverEvent(Component.text("Copy", NamedTextColor.YELLOW)) + .clickEvent(ClickEvent.suggestCommand(bData))); int id = BlockStateUtils.blockStateToId(blockState); if (!BlockStateUtils.isVanillaBlock(id)) { Object holder = BukkitBlockManager.instance().getMinecraftBlockHolder(id); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(id); if (immutableBlockState != null) { - sender.sendMessage(Component.text(immutableBlockState.toString())); + String bState = immutableBlockState.toString(); + sender.sendMessage(Component.text(bState) + .hoverEvent(Component.text("Copy", NamedTextColor.YELLOW)) + .clickEvent(ClickEvent.suggestCommand(bState))); } ImmutableBlockState dataInCache = plugin().worldManager().getWorld(block.getWorld().getUID()).getBlockStateAtIfLoaded(LocationUtils.toBlockPos(block.getLocation())); sender.sendMessage(Component.text("cache-state: " + (dataInCache != null && !dataInCache.isEmpty()))); From 0e64c48699422a9d032cf184891dea1787469517 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 3 Oct 2025 05:26:47 +0800 Subject: [PATCH 104/125] =?UTF-8?q?=E6=94=B9=E8=BF=9Bgive=E6=96=B9?= =?UTF-8?q?=E6=B3=95=EF=BC=8C=E6=94=B9=E8=BF=9B=E5=8F=91=E5=8C=85=E5=9B=BE?= =?UTF-8?q?=E8=85=BE=E7=9A=84=E8=A7=A6=E5=8F=91=E4=BB=A5=E5=8F=8A=E5=A3=B0?= =?UTF-8?q?=E9=9F=B3=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91=E5=B9=B6=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=B8=BB=E6=89=8B=E6=8B=BF=E7=9D=80=E4=B8=8D=E6=AD=BB?= =?UTF-8?q?=E5=9B=BE=E8=85=BE=E6=97=B6=E8=A7=A6=E5=8F=91=E5=8A=A8=E7=94=BB?= =?UTF-8?q?=E4=B8=8D=E6=AD=A3=E7=A1=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../command/feature/GetItemCommand.java | 6 +- .../command/feature/GiveItemCommand.java | 6 +- .../feature/TotemAnimationCommand.java | 40 +++++------ .../minecraft/NetworkReflections.java | 15 ++++ .../plugin/user/BukkitServerPlayer.java | 2 +- .../craftengine/bukkit/util/PlayerUtils.java | 71 +++++++++++++------ .../craftengine/core/sound/Sounds.java | 1 + 7 files changed, 89 insertions(+), 52 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java index 9326accf6..6e6b2e95f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GetItemCommand.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.PlayerUtils; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; @@ -61,9 +62,10 @@ public class GetItemCommand extends BukkitCommandFeature { itemId = customItem.id(); } } - Item builtItem = customItem.buildItem(BukkitAdaptors.adapt(player)); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); + Item builtItem = customItem.buildItem(serverPlayer); if (builtItem != null) { - PlayerUtils.giveItem(player, amount, builtItem); + PlayerUtils.giveItem(serverPlayer, amount, builtItem); } handleFeedback(context, MessageConstants.COMMAND_ITEM_GET_SUCCESS, Component.text(amount), Component.text(itemId.toString())); }); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java index cd66ee42a..8ffd889b1 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/GiveItemCommand.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.api.CraftEngineItems; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.PlayerUtils; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; @@ -66,9 +67,10 @@ public class GiveItemCommand extends BukkitCommandFeature { } Collection players = selector.values(); for (Player player : players) { - Item builtItem = customItem.buildItem(BukkitAdaptors.adapt(player)); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); + Item builtItem = customItem.buildItem(serverPlayer); if (builtItem != null) { - PlayerUtils.giveItem(player, amount, builtItem); + PlayerUtils.giveItem(serverPlayer, amount, builtItem); } } if (players.size() == 1) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java index 7001785f0..b7a639590 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java @@ -1,17 +1,20 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; +import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.PlayerUtils; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.ItemKeys; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; import net.momirealms.craftengine.core.plugin.command.FlagKeys; import net.momirealms.craftengine.core.plugin.locale.MessageConstants; +import net.momirealms.craftengine.core.sound.SoundData; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import org.bukkit.NamespacedKey; @@ -30,7 +33,6 @@ import org.incendo.cloud.parser.flag.CommandFlag; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; -import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -51,8 +53,7 @@ public class TotemAnimationCommand extends BukkitCommandFeature { return CompletableFuture.completedFuture(plugin().itemManager().cachedTotemSuggestions()); } })) - .flag(CommandFlag.builder("sound_event").withComponent(NamespacedKeyParser.namespacedKeyParser()).build()) - .flag(CommandFlag.builder("sound_location").withComponent(NamespacedKeyParser.namespacedKeyParser()).build()) + .flag(CommandFlag.builder("sound").withComponent(NamespacedKeyParser.namespacedKeyParser()).build()) .handler(context -> { NamespacedKey namespacedKey = context.get("id"); Key key = Key.of(namespacedKey.namespace(), namespacedKey.value()); @@ -61,28 +62,19 @@ public class TotemAnimationCommand extends BukkitCommandFeature { handleFeedback(context, MessageConstants.COMMAND_TOTEM_NOT_TOTEM, Component.text(key.toString())); return; } - Item item = customItem.buildItem(ItemBuildContext.empty()); - if (VersionHelper.isOrAbove1_21_2()) { - if (context.flags().contains("sound_location")) { - String soundResourceLocation = context.flags().getValue("sound_location").get().toString(); - if (soundResourceLocation != null) { - item.setComponent(ComponentTypes.DEATH_PROTECTION, Map.of("death_effects", List.of(Map.of("type", "play_sound", "sound", Map.of( - "sound_id", soundResourceLocation - ))))); - } - } else if (context.flags().contains("sound_event")) { - String soundEvent = context.flags().getValue("sound_event").get().toString(); - if (soundEvent != null) { - item.setComponent(ComponentTypes.DEATH_PROTECTION, Map.of("death_effects", List.of(Map.of("type", "play_sound", "sound", soundEvent)))); - } - } else { - item.setComponent(ComponentTypes.DEATH_PROTECTION, Map.of()); - } - } - ItemStack totemItem = item.getItem(); MultiplePlayerSelector selector = context.get("players"); for (Player player : selector.values()) { - PlayerUtils.sendTotemAnimation(player, totemItem); + BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); + Item item = customItem.buildItem(serverPlayer); + if (VersionHelper.isOrAbove1_21_2()) { + item.setJavaComponent(ComponentTypes.DEATH_PROTECTION, Map.of()); + } + NamespacedKey soundKey = context.flags().get("sound"); + SoundData soundData = null; + if (soundKey != null) { + soundData = SoundData.of(KeyUtils.namespacedKey2Key(soundKey), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1); + } + PlayerUtils.sendTotemAnimation(serverPlayer, item, soundData); } }); } 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 efbcc589d..e36fac81c 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 @@ -1677,4 +1677,19 @@ public final class NetworkReflections { ReflectionUtils.getConstructor(clazz$ClientboundUpdateAdvancementsPacket, boolean.class, Collection.class, Set.class, Map.class, boolean.class) : ReflectionUtils.getConstructor(clazz$ClientboundUpdateAdvancementsPacket, boolean.class, Collection.class, Set.class, Map.class) ); + + public static final Class clazz$ClientboundStopSoundPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutStopSound", + "network.protocol.game.ClientboundStopSoundPacket" + ) + ); + + public static final Constructor constructor$ClientboundStopSoundPacket = requireNonNull( + ReflectionUtils.getDeclaredConstructor( + clazz$ClientboundStopSoundPacket, + CoreReflections.clazz$ResourceLocation, + CoreReflections.clazz$SoundSource + ) + ); } 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 41aae4987..65eaf3b2f 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 @@ -379,7 +379,7 @@ public class BukkitServerPlayer extends Player { @SuppressWarnings("unchecked") @Override public void giveItem(Item item) { - PlayerUtils.giveItem(platformPlayer(), item.count(), (Item) item); + PlayerUtils.giveItem(this, item.count(), (Item) item); } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java index ae2a6a2b3..37ddf5429 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java @@ -1,22 +1,26 @@ package net.momirealms.craftengine.bukkit.util; import com.mojang.datafixers.util.Pair; -import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemKeys; +import net.momirealms.craftengine.core.sound.SoundData; +import net.momirealms.craftengine.core.sound.SoundSource; +import net.momirealms.craftengine.core.sound.Sounds; import net.momirealms.craftengine.core.util.RandomUtils; import net.momirealms.craftengine.core.util.VersionHelper; -import org.bukkit.Sound; -import org.bukkit.SoundCategory; -import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Optional; public final class PlayerUtils { private PlayerUtils() { @@ -33,7 +37,7 @@ public final class PlayerUtils { } public static void giveItem(Player player, Item original, Item item) { - Object serverPlayer = FastNMS.INSTANCE.method$CraftPlayer$getHandle(player); + Object serverPlayer = player.serverPlayer(); Object inventory = FastNMS.INSTANCE.method$Player$getInventory(serverPlayer); boolean flag = FastNMS.INSTANCE.method$Inventory$add(inventory, item.getLiteralObject()); if (flag && item.isEmpty()) { @@ -41,36 +45,57 @@ public final class PlayerUtils { if (droppedItem != null) { FastNMS.INSTANCE.method$ItemEntity$makeFakeItem(droppedItem); } - player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 0.2F, ((RandomUtils.generateRandomFloat(0, 1) - RandomUtils.generateRandomFloat(0, 1)) * 0.7F + 1.0F) * 2.0F); + player.world().playSound(player.position(), Sounds.ENTITY_ITEM_PICKUP, 0.2F, ((RandomUtils.generateRandomFloat(0, 1) - RandomUtils.generateRandomFloat(0, 1)) * 0.7F + 1.0F) * 2.0F, SoundSource.PLAYER); FastNMS.INSTANCE.method$AbstractContainerMenu$broadcastChanges(FastNMS.INSTANCE.field$Player$containerMenu(serverPlayer)); } else { Object droppedItem = FastNMS.INSTANCE.method$ServerPlayer$drop(serverPlayer, item.getLiteralObject(), false, false, !VersionHelper.isOrAbove1_21_5(), null); if (droppedItem != null) { FastNMS.INSTANCE.method$ItemEntity$setNoPickUpDelay(droppedItem); - FastNMS.INSTANCE.method$ItemEntity$setTarget(droppedItem, player.getUniqueId()); + FastNMS.INSTANCE.method$ItemEntity$setTarget(droppedItem, player.uuid()); } } } - public static void sendTotemAnimation(Player player, ItemStack totem) { - ItemStack offhandItem = player.getInventory().getItemInOffHand(); + public static void sendTotemAnimation(Player player, Item totem, @Nullable SoundData sound) { List packets = new ArrayList<>(); try { - Object previousItem = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(offhandItem); - Object totemItem = FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(totem); + Object totemItem = totem.getLiteralObject(); + Item previousMainHandItem = player.getItemInHand(InteractionHand.MAIN_HAND); + boolean flag = previousMainHandItem.id().equals(ItemKeys.TOTEM_OF_UNDYING); + Object previousOffHandItem = player.getItemInHand(InteractionHand.OFF_HAND).getLiteralObject(); - Object packet1 = NetworkReflections.constructor$ClientboundSetEquipmentPacket - .newInstance(player.getEntityId(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, totemItem))); - Object packet2 = NetworkReflections.constructor$ClientboundEntityEventPacket - .newInstance(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player), (byte) 35); - Object packet3 = NetworkReflections.constructor$ClientboundSetEquipmentPacket - .newInstance(player.getEntityId(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, previousItem))); - packets.add(packet1); - packets.add(packet2); - packets.add(packet3); + if (flag) { + packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance( + player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$MAINHAND, BukkitItemManager.instance().uniqueEmptyItem().item().getLiteralObject())) + )); + } + packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance( + player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, totemItem)) + )); + packets.add(NetworkReflections.constructor$ClientboundEntityEventPacket.newInstance(player.serverPlayer(), (byte) 35)); + if (flag) { + packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance( + player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$MAINHAND, previousMainHandItem.getLiteralObject())) + )); + } + packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance( + player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, previousOffHandItem)) + )); - Object bundlePacket = FastNMS.INSTANCE.constructor$ClientboundBundlePacket(packets); - BukkitNetworkManager.instance().sendPacket(BukkitAdaptors.adapt(player), bundlePacket); + if (sound != null) { + packets.add(NetworkReflections.constructor$ClientboundStopSoundPacket.newInstance( + FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.totem.use"), + CoreReflections.instance$SoundSource$PLAYERS + )); + packets.add(FastNMS.INSTANCE.constructor$ClientboundSoundPacket( + FastNMS.INSTANCE.method$Holder$direct(FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(sound.id()), Optional.empty())), + CoreReflections.instance$SoundSource$PLAYERS, + player.x(), player.y(), player.z(), sound.volume().get(), sound.pitch().get(), + RandomUtils.generateRandomLong() + )); + } + + player.sendPackets(packets, false); } catch (ReflectiveOperationException e) { BukkitCraftEngine.instance().logger().warn("Failed to send totem animation"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/Sounds.java b/core/src/main/java/net/momirealms/craftengine/core/sound/Sounds.java index 252754c00..73630f4e1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/Sounds.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/Sounds.java @@ -43,4 +43,5 @@ public final class Sounds { public static final Key BAMBOO_WOOD_BUTTON_CLICK_ON = Key.of("block.bamboo_wood_button.click_on"); public static final Key WOODEN_BUTTON_CLICK_OFF = Key.of("block.wooden_button.click_off"); public static final Key WOODEN_BUTTON_CLICK_ON = Key.of("block.wooden_button.click_on"); + public static final Key ENTITY_ITEM_PICKUP = Key.of("entity.item.pickup"); } From 1d759d57d5f66def2a2ee5c3df5eec0ff0fae507 Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Fri, 3 Oct 2025 14:33:24 +0800 Subject: [PATCH 105/125] =?UTF-8?q?=E8=BF=9B=E4=B8=80=E6=AD=A51.21.10?= =?UTF-8?q?=E5=85=BC=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/reflection/minecraft/CoreReflections.java | 8 +++++--- .../momirealms/craftengine/core/block/BlockBehavior.java | 4 ++-- gradle.properties | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) 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 0d4bdd343..6cc1e3c7d 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 @@ -3547,9 +3547,11 @@ public final class CoreReflections { ); public static final Method method$BlockBehaviour$entityInside = requireNonNull( - VersionHelper.isOrAbove1_21_5() ? - ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"entityInside", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Entity, clazz$InsideBlockEffectApplier) : - ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"entityInside", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Entity) + VersionHelper.isOrAbove1_21_10() + ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"entityInside", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Entity, clazz$InsideBlockEffectApplier, boolean.class) + : VersionHelper.isOrAbove1_21_5() + ? ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"entityInside", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Entity, clazz$InsideBlockEffectApplier) + : ReflectionUtils.getDeclaredMethod(clazz$BlockBehaviour, void.class, new String[]{"entityInside", "a"}, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$Entity) ); // 1.21.5+ 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 738dd94ea..de57acac4 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 @@ -100,8 +100,7 @@ public abstract class BlockBehavior { return false; } - // 1.20.1~1.21.8 BlockState state, Level level, BlockPos pos - // 1.21.9+ BlockState state, Level level, BlockPos pos + // BlockState state, Level level, BlockPos pos public int getAnalogOutputSignal(Object thisBlock, Object[] args) throws Exception { return 0; } @@ -143,6 +142,7 @@ public abstract class BlockBehavior { // 1.20-1.21.4 BlockState state, Level level, BlockPos pos, Entity entity // 1.21.5+ BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier + // 1.21.10+ BlockState state, Level level, BlockPos pos, Entity entity, InsideBlockEffectApplier effectApplier, boolean flag public void entityInside(Object thisBlock, Object[] args, Callable superMethod) throws Exception { } diff --git a/gradle.properties b/gradle.properties index f50bd8c61..407ffae46 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.100 +nms_helper_version=1.0.101 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5 From 7504b5cad6db8302a0f45a146689fa183118074e Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Fri, 3 Oct 2025 22:08:09 +0800 Subject: [PATCH 106/125] =?UTF-8?q?=E9=85=8D=E6=96=B9=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E9=A1=BA=E5=BA=8F=E6=9C=89=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../craftengine/core/item/recipe/AbstractRecipeManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 22c095387..93d1ea157 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 @@ -17,7 +17,7 @@ import java.util.*; public abstract class AbstractRecipeManager implements RecipeManager { protected final Map>> byType = new EnumMap<>(RecipeType.class); - protected final Map> byId = new HashMap<>(); + protected final Map> byId = new LinkedHashMap<>(); protected final Map>> byResult = new HashMap<>(); protected final Map>> byIngredient = new HashMap<>(); protected final Set dataPackRecipes = new HashSet<>(); From ccda02e46830b989534bc7af9aad4bb4d9aa53cc Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Fri, 3 Oct 2025 22:58:31 +0800 Subject: [PATCH 107/125] =?UTF-8?q?=E6=94=B9=E8=BF=9Btotem=E6=8C=87?= =?UTF-8?q?=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../feature/TotemAnimationCommand.java | 34 +++++++++++++++---- .../craftengine/bukkit/util/PlayerUtils.java | 21 +++++++----- .../craftengine/core/plugin/CraftEngine.java | 1 + .../core/sound/AbstractSoundManager.java | 18 ++++++++++ .../craftengine/core/sound/SoundData.java | 5 +++ .../craftengine/core/sound/SoundManager.java | 4 +++ 6 files changed, 68 insertions(+), 15 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java index b7a639590..03aac1937 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java @@ -30,10 +30,12 @@ import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser; import org.incendo.cloud.context.CommandContext; import org.incendo.cloud.context.CommandInput; import org.incendo.cloud.parser.flag.CommandFlag; +import org.incendo.cloud.parser.standard.FloatParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; import java.util.Map; +import java.util.Optional; import java.util.concurrent.CompletableFuture; public class TotemAnimationCommand extends BukkitCommandFeature { @@ -46,6 +48,7 @@ public class TotemAnimationCommand extends BukkitCommandFeature { public Command.Builder assembleCommand(CommandManager manager, Command.Builder builder) { return builder .flag(FlagKeys.SILENT_FLAG) + .flag(CommandFlag.builder("no-sound")) .required("players", MultiplePlayerSelectorParser.multiplePlayerSelectorParser()) .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { @Override @@ -53,7 +56,16 @@ public class TotemAnimationCommand extends BukkitCommandFeature { return CompletableFuture.completedFuture(plugin().itemManager().cachedTotemSuggestions()); } })) - .flag(CommandFlag.builder("sound").withComponent(NamespacedKeyParser.namespacedKeyParser()).build()) + .optional("sound", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { + @Override + public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { + return CompletableFuture.completedFuture(plugin().soundManager().cachedSoundSuggestions()); + } + })) + .optional("volume", FloatParser.floatParser(0f)) + .optional("pitch", FloatParser.floatParser(0f, 2f)) + .optional("min-volume", FloatParser.floatParser(0f)) + .optional("min-pitch", FloatParser.floatParser(0f, 2f)) .handler(context -> { NamespacedKey namespacedKey = context.get("id"); Key key = Key.of(namespacedKey.namespace(), namespacedKey.value()); @@ -62,6 +74,16 @@ public class TotemAnimationCommand extends BukkitCommandFeature { handleFeedback(context, MessageConstants.COMMAND_TOTEM_NOT_TOTEM, Component.text(key.toString())); return; } + Optional soundKey = context.optional("sound"); + SoundData soundData = null; + if (soundKey.isPresent()) { + float volume = context.getOrDefault("volume", 1.0f); + float pitch = context.getOrDefault("pitch", 1.0f); + float minVolume = context.getOrDefault("min-volume", 1.0f); + float minPitch = context.getOrDefault("min-pitch", 1.0f); + soundData = SoundData.of(KeyUtils.namespacedKey2Key(soundKey.get()), SoundData.SoundValue.ranged(minVolume, volume), SoundData.SoundValue.ranged(minPitch, pitch)); + } + boolean removeSound = context.flags().hasFlag("no-sound"); MultiplePlayerSelector selector = context.get("players"); for (Player player : selector.values()) { BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); @@ -69,13 +91,11 @@ public class TotemAnimationCommand extends BukkitCommandFeature { if (VersionHelper.isOrAbove1_21_2()) { item.setJavaComponent(ComponentTypes.DEATH_PROTECTION, Map.of()); } - NamespacedKey soundKey = context.flags().get("sound"); - SoundData soundData = null; - if (soundKey != null) { - soundData = SoundData.of(KeyUtils.namespacedKey2Key(soundKey), SoundData.SoundValue.FIXED_1, SoundData.SoundValue.FIXED_1); - } - PlayerUtils.sendTotemAnimation(serverPlayer, item, soundData); + // TODO 存在第一次进服 未正确移除图腾声音的问题 + PlayerUtils.sendTotemAnimation(serverPlayer, item, soundData, removeSound); } + + // TODO 消息提示 }); } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java index 37ddf5429..c0b242549 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/PlayerUtils.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.util; import com.mojang.datafixers.util.Pair; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; @@ -56,15 +57,19 @@ public final class PlayerUtils { } } - public static void sendTotemAnimation(Player player, Item totem, @Nullable SoundData sound) { + public static void sendTotemAnimation(Player player, Item totem, @Nullable SoundData sound, boolean removeSound) { List packets = new ArrayList<>(); try { Object totemItem = totem.getLiteralObject(); Item previousMainHandItem = player.getItemInHand(InteractionHand.MAIN_HAND); - boolean flag = previousMainHandItem.id().equals(ItemKeys.TOTEM_OF_UNDYING); + boolean isMainHandTotem; + if (VersionHelper.isOrAbove1_21_2()) { + isMainHandTotem = previousMainHandItem.hasComponent(ComponentTypes.DEATH_PROTECTION); + } else { + isMainHandTotem = previousMainHandItem.id().equals(ItemKeys.TOTEM_OF_UNDYING); + } Object previousOffHandItem = player.getItemInHand(InteractionHand.OFF_HAND).getLiteralObject(); - - if (flag) { + if (isMainHandTotem) { packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance( player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$MAINHAND, BukkitItemManager.instance().uniqueEmptyItem().item().getLiteralObject())) )); @@ -73,7 +78,7 @@ public final class PlayerUtils { player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, totemItem)) )); packets.add(NetworkReflections.constructor$ClientboundEntityEventPacket.newInstance(player.serverPlayer(), (byte) 35)); - if (flag) { + if (isMainHandTotem) { packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance( player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$MAINHAND, previousMainHandItem.getLiteralObject())) )); @@ -81,12 +86,13 @@ public final class PlayerUtils { packets.add(NetworkReflections.constructor$ClientboundSetEquipmentPacket.newInstance( player.entityID(), List.of(Pair.of(CoreReflections.instance$EquipmentSlot$OFFHAND, previousOffHandItem)) )); - - if (sound != null) { + if (sound != null || removeSound) { packets.add(NetworkReflections.constructor$ClientboundStopSoundPacket.newInstance( FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", "item.totem.use"), CoreReflections.instance$SoundSource$PLAYERS )); + } + if (sound != null) { packets.add(FastNMS.INSTANCE.constructor$ClientboundSoundPacket( FastNMS.INSTANCE.method$Holder$direct(FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(sound.id()), Optional.empty())), CoreReflections.instance$SoundSource$PLAYERS, @@ -94,7 +100,6 @@ public final class PlayerUtils { RandomUtils.generateRandomLong() )); } - player.sendPackets(packets, false); } catch (ReflectiveOperationException e) { BukkitCraftEngine.instance().logger().warn("Failed to send totem animation"); 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 31327c6c2..3b83cedc0 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 @@ -172,6 +172,7 @@ public abstract class CraftEngine implements Plugin { // collect illegal characters from minecraft:default font this.fontManager.delayedLoad(); this.advancementManager.delayedLoad(); + this.soundManager.delayedLoad(); if (reloadRecipe) { // convert data pack recipes this.recipeManager.delayedLoad(); 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 3c5886417..0972a6eed 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 @@ -8,6 +8,7 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.config.IdSectionConfigParser; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.*; +import org.incendo.cloud.suggestion.Suggestion; import java.nio.file.Path; import java.util.*; @@ -21,6 +22,7 @@ public abstract class AbstractSoundManager implements SoundManager { protected final SoundParser soundParser; protected final SongParser songParser; protected final Map customSoundsInRegistry = new HashMap<>(); + protected final List soundSuggestions = new ArrayList<>(); public AbstractSoundManager(CraftEngine plugin) { this.plugin = plugin; @@ -43,6 +45,22 @@ public abstract class AbstractSoundManager implements SoundManager { this.byId.clear(); this.byNamespace.clear(); this.songs.clear(); + this.soundSuggestions.clear(); + } + + @Override + public void delayedLoad() { + for (Key key : VANILLA_SOUND_EVENTS) { + this.soundSuggestions.add(Suggestion.suggestion(key.asString())); + } + for (Key key : this.byId.keySet()) { + this.soundSuggestions.add(Suggestion.suggestion(key.asString())); + } + } + + @Override + public List cachedSoundSuggestions() { + return this.soundSuggestions; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundData.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundData.java index 339c860ae..af0356c6e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundData.java @@ -57,6 +57,11 @@ public record SoundData(Key id, SoundValue volume, SoundValue pitch) { } static SoundValue ranged(float min, float max) { + if (min > max) { + return new Ranged(max, min); + } else if (min == max) { + return SoundValue.fixed(max); + } return new Ranged(min, max); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java index 55eeb6e4b..10ca914c1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/sound/SoundManager.java @@ -3,7 +3,9 @@ package net.momirealms.craftengine.core.sound; import net.momirealms.craftengine.core.plugin.Manageable; import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.util.Key; +import org.incendo.cloud.suggestion.Suggestion; +import java.util.List; import java.util.Map; public interface SoundManager extends Manageable { @@ -12,5 +14,7 @@ public interface SoundManager extends Manageable { ConfigParser[] parsers(); + List cachedSoundSuggestions(); + Map sounds(); } From 222b2b028f1fd3df88170bed1bd62c82dd7f3629 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Fri, 3 Oct 2025 23:08:28 +0800 Subject: [PATCH 108/125] Update topaz_tool_weapon.yml --- .../configuration/items/topaz_tool_weapon.yml | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml b/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml index 3e2114151..24e045878 100644 --- a/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml +++ b/common-files/src/main/resources/resources/default/configuration/items/topaz_tool_weapon.yml @@ -52,8 +52,7 @@ items: data: item-name: <#FF8C00> tooltip-style: minecraft:topaz - components: - minecraft:max_damage: 64 + max-damage: 64 model: template: default:model/simplified_handheld arguments: @@ -66,8 +65,7 @@ items: data: item-name: <#FF8C00> tooltip-style: minecraft:topaz - components: - minecraft:max_damage: 64 + max-damage: 64 model: template: default:model/simplified_handheld arguments: @@ -80,8 +78,7 @@ items: data: item-name: <#FF8C00> tooltip-style: minecraft:topaz - components: - minecraft:max_damage: 64 + max-damage: 64 model: template: default:model/simplified_handheld arguments: @@ -94,8 +91,7 @@ items: data: item-name: <#FF8C00> tooltip-style: minecraft:topaz - components: - minecraft:max_damage: 64 + max-damage: 64 model: template: default:model/simplified_handheld arguments: @@ -108,8 +104,7 @@ items: data: item-name: <#FF8C00> tooltip-style: minecraft:topaz - components: - minecraft:max_damage: 64 + max-damage: 64 model: template: default:model/simplified_handheld arguments: @@ -129,8 +124,7 @@ items: data: item-name: <#FF8C00> tooltip-style: minecraft:topaz - components: - minecraft:max_damage: 300 + max-damage: 300 model: type: minecraft:select property: minecraft:display_context From 319c88172b71c8572546a5274ad8b0216be83dd6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 4 Oct 2025 03:49:15 +0800 Subject: [PATCH 109/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E7=BB=84=E4=BB=B6=E9=87=8C=E7=89=A9=E5=93=81=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plugin/network/BukkitNetworkManager.java | 111 ++++++++++++++++-- .../craftengine/bukkit/util/KeyUtils.java | 5 + .../core/util/AdventureHelper.java | 36 ++++-- gradle.properties | 2 +- 4 files changed, 132 insertions(+), 22 deletions(-) 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 733013ca6..e0f6210a7 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 @@ -2,8 +2,11 @@ package net.momirealms.craftengine.bukkit.plugin.network; import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import com.google.gson.JsonElement; import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.datafixers.util.Either; +import com.mojang.serialization.DataResult; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.*; @@ -15,7 +18,10 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntList; +import net.kyori.adventure.nbt.api.BinaryTagHolder; import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.DataComponentValue; +import net.kyori.adventure.text.event.HoverEvent; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent; @@ -84,7 +90,9 @@ import net.momirealms.craftengine.core.world.chunk.PalettedContainer; import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; import net.momirealms.craftengine.core.world.chunk.packet.MCSection; import net.momirealms.craftengine.core.world.collision.AABB; +import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; +import net.momirealms.sparrow.nbt.adventure.NBTDataComponentValue; import org.bukkit.*; import org.bukkit.World; import org.bukkit.block.Block; @@ -2377,39 +2385,122 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - public static class SystemChatListener1_20 implements ByteBufferPacketListener { + @SuppressWarnings("all") + public HoverEvent.ShowItem replaceShowItem(HoverEvent.ShowItem showItem, BukkitServerPlayer player) { + Object nmsItemStack; + if (VersionHelper.COMPONENT_RELEASE) { + CompoundTag itemTag = new CompoundTag(); + itemTag.putInt("count", showItem.count()); + itemTag.putString("id", showItem.item().asMinimalString()); + Map components = showItem.dataComponents(); + if (!components.isEmpty()) { + CompoundTag componentsTag = new CompoundTag(); + Map componentsMap = showItem.dataComponentsAs(NBTDataComponentValue.class); + for (Map.Entry entry : componentsMap.entrySet()) { + componentsTag.put(entry.getKey().asMinimalString(), entry.getValue().tag()); + } + itemTag.put("components", componentsTag); + } + DataResult nmsItemStackResult = CoreReflections.instance$ItemStack$CODEC.parse(MRegistryOps.SPARROW_NBT, itemTag); + Optional result = nmsItemStackResult.result(); + if (result.isEmpty()) { + return showItem; + } + nmsItemStack = result.get(); + } else { + Object compoundTag = FastNMS.INSTANCE.constructor$CompoundTag(); + FastNMS.INSTANCE.method$CompoundTag$put(compoundTag, "Count", FastNMS.INSTANCE.constructor$IntTag(showItem.count())); + FastNMS.INSTANCE.method$CompoundTag$put(compoundTag, "id", FastNMS.INSTANCE.constructor$StringTag(showItem.item().asMinimalString())); + BinaryTagHolder nbt = showItem.nbt(); + if (nbt != null) { + try { + Object nmsTag = FastNMS.INSTANCE.method$TagParser$parseCompoundFully(nbt.string()); + FastNMS.INSTANCE.method$CompoundTag$put(compoundTag, "tag", nmsTag); + } catch (CommandSyntaxException ignored) { + return showItem; + } + } + nmsItemStack = FastNMS.INSTANCE.method$ItemStack$of(compoundTag); + } + + Item wrap = this.plugin.itemManager().wrap(FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack)); + Item clientBoundItem = this.plugin.itemManager().s2c(wrap, player); + if (clientBoundItem.isEmpty()) { + return showItem; + } + net.kyori.adventure.key.Key id = KeyUtils.toAdventureKey(clientBoundItem.vanillaId()); + int count = clientBoundItem.count(); + if (VersionHelper.COMPONENT_RELEASE) { + DataResult tagDataResult = CoreReflections.instance$ItemStack$CODEC.encodeStart(MRegistryOps.SPARROW_NBT, clientBoundItem.getLiteralObject()); + Optional result = tagDataResult.result(); + if (result.isEmpty()) { + return showItem; + } + CompoundTag itemTag = (CompoundTag) result.get(); + CompoundTag componentsTag = itemTag.getCompound("components"); + if (componentsTag != null) { + Map componentsMap = new HashMap<>(); + for (Map.Entry entry : componentsTag.entrySet()) { + componentsMap.put(net.kyori.adventure.key.Key.key(entry.getKey()), NBTDataComponentValue.of(entry.getValue())); + } + return HoverEvent.ShowItem.showItem(id, count, componentsMap); + } else { + return HoverEvent.ShowItem.showItem(id, count); + } + } else { + Object tag = FastNMS.INSTANCE.method$ItemStack$getTag(clientBoundItem.getLiteralObject()); + if (tag != null) { + return HoverEvent.ShowItem.showItem(id, count, BinaryTagHolder.binaryTagHolder(tag.toString())); + } else { + return HoverEvent.ShowItem.showItem(id, count); + } + } + } + + public class SystemChatListener1_20 implements ByteBufferPacketListener { @Override public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { - if (!Config.interceptSystemChat()) return; FriendlyByteBuf buf = event.getBuffer(); String jsonOrPlainString = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(jsonOrPlainString); - if (tokens.isEmpty()) return; + Tag tag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, GsonHelper.get().fromJson(jsonOrPlainString, JsonElement.class)); + Component component = AdventureHelper.nbtToComponent(tag); boolean overlay = buf.readBoolean(); event.setChanged(true); buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(jsonOrPlainString), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + if (Config.interceptSystemChat()) { + Map tokens = CraftEngine.instance().fontManager().matchTags(jsonOrPlainString); + if (!tokens.isEmpty()) { + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)); + } + } + component = AdventureHelper.replaceShowItem(component, s -> replaceShowItem(s, (BukkitServerPlayer) user)); + buf.writeUtf(MRegistryOps.SPARROW_NBT.convertTo(MRegistryOps.JSON, AdventureHelper.componentToNbt(component)).toString()); buf.writeBoolean(overlay); } } - public static class SystemChatListener1_20_3 implements ByteBufferPacketListener { + public class SystemChatListener1_20_3 implements ByteBufferPacketListener { @Override public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { - if (!Config.interceptSystemChat()) return; FriendlyByteBuf buf = event.getBuffer(); Tag nbt = buf.readNbt(false); if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; boolean overlay = buf.readBoolean(); event.setChanged(true); buf.clear(); buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + Component component = AdventureHelper.tagToComponent(nbt); + if (Config.interceptSystemChat()) { + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (!tokens.isEmpty()) { + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)); + } + } + component = AdventureHelper.replaceShowItem(component, s -> replaceShowItem(s, (BukkitServerPlayer) user)); + buf.writeNbt(AdventureHelper.componentToTag(component), false); buf.writeBoolean(overlay); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/KeyUtils.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/KeyUtils.java index dd8b78790..845d70bd2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/KeyUtils.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/util/KeyUtils.java @@ -19,6 +19,11 @@ public final class KeyUtils { return Key.of(key.namespace(), key.value()); } + @SuppressWarnings("all") + public static net.kyori.adventure.key.Key toAdventureKey(Key key) { + return net.kyori.adventure.key.Key.key(key.namespace(), key.value()); + } + public static Object toResourceLocation(String namespace, String path) { return FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath(namespace, path); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java index c17579e65..6b9b9c720 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/AdventureHelper.java @@ -5,6 +5,7 @@ import net.kyori.adventure.text.Component; import net.kyori.adventure.text.ComponentIteratorType; import net.kyori.adventure.text.TextComponent; import net.kyori.adventure.text.TextReplacementConfig; +import net.kyori.adventure.text.event.HoverEvent; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -18,6 +19,7 @@ import net.momirealms.sparrow.nbt.adventure.NBTComponentSerializer; import net.momirealms.sparrow.nbt.adventure.NBTSerializerOptions; import java.util.*; +import java.util.function.Function; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -52,32 +54,30 @@ public class AdventureHelper { this.miniMessage = MiniMessage.builder().build(); this.miniMessageStrict = MiniMessage.builder().strict(true).build(); this.miniMessageCustom = MiniMessage.builder().tags(TagResolver.empty()).build(); - GsonComponentSerializer.Builder builder = GsonComponentSerializer.builder(); + GsonComponentSerializer.Builder gsonBuilder = GsonComponentSerializer.builder(); if (!VersionHelper.isOrAbove1_20_5()) { - builder.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get()); - builder.editOptions((b) -> b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, false)); + gsonBuilder.legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get()); + gsonBuilder.editOptions((b) -> b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_ID_AS_INT_ARRAY, false)); } if (!VersionHelper.isOrAbove1_21_5()) { - builder.editOptions((b) -> { + gsonBuilder.editOptions((b) -> { b.value(JSONOptions.EMIT_CLICK_EVENT_TYPE, JSONOptions.ClickEventValueMode.CAMEL_CASE); b.value(JSONOptions.EMIT_HOVER_EVENT_TYPE, JSONOptions.HoverEventValueMode.CAMEL_CASE); b.value(JSONOptions.EMIT_HOVER_SHOW_ENTITY_KEY_AS_TYPE_AND_UUID_AS_ID, true); }); } this.legacyComponentSerializer = LegacyComponentSerializer.builder().build(); - this.gsonComponentSerializer = builder.build(); + this.gsonComponentSerializer = gsonBuilder.build(); this.nbtComponentSerializer = NBTComponentSerializer.builder() - .editItem(item -> { - if (VersionHelper.isOrAbove1_20_5()) { - } - }) .editOptions((b) -> { if (!VersionHelper.isOrAbove1_21_5()) { b.value(NBTSerializerOptions.EMIT_CLICK_EVENT_TYPE, false); b.value(NBTSerializerOptions.EMIT_HOVER_EVENT_TYPE, false); } - }) - .build(); + if (!VersionHelper.isOrAbove1_20_5()) { + b.value(NBTSerializerOptions.DATA_COMPONENT_RELEASE, false); + } + }).build(); } private static class SingletonHolder { @@ -170,6 +170,19 @@ public class AdventureHelper { return getNBT().deserialize(tag); } + public static Component replaceShowItem(Component component, Function replacer) { + HoverEvent hoverEvent = component.hoverEvent(); + if (hoverEvent != null && hoverEvent.action() == HoverEvent.Action.SHOW_ITEM) { + Object showItem = hoverEvent.value(); + component = component.hoverEvent(HoverEvent.showItem(replacer.apply((HoverEvent.ShowItem) showItem))); + } + List newChildren = new ArrayList<>(); + for (Component child : component.children()) { + newChildren.add(replaceShowItem(child, replacer)); + } + return component.children(newChildren); + } + public static List splitLines(Component component) { List result = new ArrayList<>(1); Component line = Component.empty(); @@ -301,6 +314,7 @@ public class AdventureHelper { } public static Component replaceText(Component text, Map replacements, Context context) { + if (replacements.isEmpty()) return text; String patternString = replacements.keySet().stream() .map(Pattern::quote) .collect(Collectors.joining("|")); diff --git a/gradle.properties b/gradle.properties index 407ffae46..c7aaf559b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,7 +39,7 @@ zstd_version=1.5.7-4 commons_io_version=2.20.0 commons_imaging_version=1.0.0-alpha6 commons_lang3_version=3.19.0 -sparrow_nbt_version=0.9.4 +sparrow_nbt_version=0.9.8 sparrow_util_version=0.51 fastutil_version=8.5.16 netty_version=4.1.127.Final From 8f014a81999ba82992bce84e5188c09f82bb9a2f Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 4 Oct 2025 17:38:32 +0800 Subject: [PATCH 110/125] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8F=8D=E7=86=8A?= =?UTF-8?q?=E5=BA=93=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/build.gradle.kts | 2 +- bukkit/legacy/build.gradle.kts | 2 +- bukkit/loader/build.gradle.kts | 2 +- bukkit/paper-loader/build.gradle.kts | 2 +- .../momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java | 1 + core/build.gradle.kts | 2 +- gradle.properties | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bukkit/build.gradle.kts b/bukkit/build.gradle.kts index ec25aa893..2067a6a4a 100644 --- a/bukkit/build.gradle.kts +++ b/bukkit/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-rc2" + id("com.gradleup.shadow") version "9.2.2" id("maven-publish") } diff --git a/bukkit/legacy/build.gradle.kts b/bukkit/legacy/build.gradle.kts index 5703f4c6f..0434654d8 100644 --- a/bukkit/legacy/build.gradle.kts +++ b/bukkit/legacy/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-rc2" + id("com.gradleup.shadow") version "9.2.2" } repositories { diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index 11ecaf4e1..547fbb2b0 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-rc2" + id("com.gradleup.shadow") version "9.2.2" id("de.eldoria.plugin-yml.bukkit") version "0.7.1" } diff --git a/bukkit/paper-loader/build.gradle.kts b/bukkit/paper-loader/build.gradle.kts index ca26d2289..293cfb09f 100644 --- a/bukkit/paper-loader/build.gradle.kts +++ b/bukkit/paper-loader/build.gradle.kts @@ -1,7 +1,7 @@ import net.minecrell.pluginyml.paper.PaperPluginDescription plugins { - id("com.gradleup.shadow") version "9.0.0-rc2" + id("com.gradleup.shadow") version "9.2.2" id("de.eldoria.plugin-yml.paper") version "0.7.1" } 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 fe991ca7f..43c8a652d 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 @@ -401,6 +401,7 @@ public class BukkitCraftEngine extends CraftEngine { this.antiGrief = AntiGriefLib.builder(this.javaPlugin) .ignoreOP(true) .silentLogs(false) + .bypassPermission("craftengine.antigrief.bypass") .build(); } return this.antiGrief; diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 58d4ada3e..a597ad742 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("com.gradleup.shadow") version "9.0.0-rc2" + id("com.gradleup.shadow") version "9.2.2" id("maven-publish") } diff --git a/gradle.properties b/gradle.properties index c7aaf559b..a1115c45f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -49,7 +49,7 @@ mojang_brigadier_version=1.0.18 byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 -anti_grief_version=0.20 +anti_grief_version=1.0.2 nms_helper_version=1.0.101 evalex_version=3.5.0 reactive_streams_version=1.0.4 From 8a17cad621b5c4043825b3eff45cfac39cd2571c Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Sat, 4 Oct 2025 20:14:15 +0800 Subject: [PATCH 111/125] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=9B=BE=E8=85=BE?= =?UTF-8?q?=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../model/bettermodel/BetterModelModel.java | 2 +- .../model/modelengine/ModelEngineModel.java | 2 +- .../block/behavior/FallingBlockBehavior.java | 12 ++--- .../bukkit/entity/BukkitEntity.java | 45 ++++++++++++++----- .../bukkit/entity/data/BaseEntityData.java | 2 +- ...eEntityData.java => BukkitEntityData.java} | 10 ++++- .../bukkit/entity/data/EntityData.java | 40 ----------------- .../bukkit/entity/data/EntityDataValue.java | 2 +- .../feature/TotemAnimationCommand.java | 15 +++++-- .../plugin/network/BukkitNetworkManager.java | 4 +- .../reflection/leaves/LeavesReflections.java | 22 ++++++--- .../reflection/minecraft/MSoundEvents.java | 19 +++----- .../plugin/user/BukkitServerPlayer.java | 29 +++++++++--- .../src/main/resources/translations/en.yml | 2 + .../src/main/resources/translations/zh_cn.yml | 2 + .../craftengine/core/entity/Entity.java | 15 ++++++- .../core/entity/data/EntityData.java | 35 +++++++++++++++ .../core/plugin/locale/MessageConstants.java | 2 + gradle.properties | 4 +- 19 files changed, 171 insertions(+), 93 deletions(-) rename bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/{SimpleEntityData.java => BukkitEntityData.java} (74%) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/entity/data/EntityData.java diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelModel.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelModel.java index bfda089ba..1a8008a7c 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelModel.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/bettermodel/BetterModelModel.java @@ -16,7 +16,7 @@ public class BetterModelModel extends AbstractExternalModel { @Override public void bindModel(AbstractEntity entity) { - org.bukkit.entity.Entity bukkitEntity = (org.bukkit.entity.Entity) entity.literalObject(); + org.bukkit.entity.Entity bukkitEntity = (org.bukkit.entity.Entity) entity.platformEntity(); BetterModelUtils.bindModel(bukkitEntity, id()); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineModel.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineModel.java index a4d35dc4e..7d7943aa2 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineModel.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/model/modelengine/ModelEngineModel.java @@ -16,7 +16,7 @@ public class ModelEngineModel extends AbstractExternalModel { @Override public void bindModel(AbstractEntity entity) { - org.bukkit.entity.Entity bukkitEntity = (org.bukkit.entity.Entity) entity.literalObject(); + org.bukkit.entity.Entity bukkitEntity = (org.bukkit.entity.Entity) entity.platformEntity(); ModelEngineUtils.bindModel(bukkitEntity, id()); } } 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 f71bbf15b..a9fb489ba 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 @@ -1,6 +1,8 @@ package net.momirealms.craftengine.bukkit.block.behavior; +import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.entity.BukkitEntity; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; @@ -80,8 +82,8 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { public void onBrokenAfterFall(Object thisBlock, Object[] args) throws Exception { Object level = args[0]; Object fallingBlockEntity = args[2]; - Object entityData = CoreReflections.field$Entity$entityData.get(fallingBlockEntity); - if (!BaseEntityData.Silent.get(entityData)) { + BukkitEntity entity = BukkitAdaptors.adapt(FastNMS.INSTANCE.method$Entity$getBukkitEntity(fallingBlockEntity)); + if (!entity.getEntityData(BaseEntityData.Silent)) { Object blockState = CoreReflections.field$FallingBlockEntity$blockState.get(fallingBlockEntity); Optional optionalCustomState = BlockStateUtils.getOptionalCustomBlockState(blockState); if (optionalCustomState.isEmpty()) return; @@ -94,16 +96,16 @@ public class FallingBlockBehavior extends BukkitBlockBehavior { } @Override - public void onLand(Object thisBlock, Object[] args) throws Exception { + public void onLand(Object thisBlock, Object[] args) { Object fallingBlock = args[4]; Object level = args[0]; Object pos = args[1]; - Object entityData = CoreReflections.field$Entity$entityData.get(fallingBlock); + BukkitEntity entity = BukkitAdaptors.adapt(FastNMS.INSTANCE.method$Entity$getBukkitEntity(fallingBlock)); Object blockState = args[2]; int stateId = BlockStateUtils.blockStateToId(blockState); ImmutableBlockState immutableBlockState = BukkitBlockManager.instance().getImmutableBlockState(stateId); if (immutableBlockState == null || immutableBlockState.isEmpty()) return; - if (!BaseEntityData.Silent.get(entityData)) { + if (!entity.getEntityData(BaseEntityData.Silent)) { net.momirealms.craftengine.core.world.World world = new BukkitWorld(FastNMS.INSTANCE.method$Level$getCraftWorld(level)); if (this.landSound != null) { world.playBlockSound(Vec3d.atCenterOf(LocationUtils.fromBlockPos(pos)), this.landSound); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java index caf677a3a..667fbf44c 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/BukkitEntity.java @@ -1,8 +1,10 @@ package net.momirealms.craftengine.bukkit.entity; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.EntityUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.entity.AbstractEntity; +import net.momirealms.craftengine.core.entity.data.EntityData; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.World; @@ -19,17 +21,17 @@ public class BukkitEntity extends AbstractEntity { @Override public double x() { - return literalObject().getX(); + return platformEntity().getX(); } @Override public double y() { - return literalObject().getY(); + return platformEntity().getY(); } @Override public double z() { - return literalObject().getZ(); + return platformEntity().getZ(); } @Override @@ -38,22 +40,22 @@ public class BukkitEntity extends AbstractEntity { @Override public int entityID() { - return literalObject().getEntityId(); + return platformEntity().getEntityId(); } @Override public float xRot() { - return literalObject().getYaw(); + return platformEntity().getYaw(); } @Override public float yRot() { - return literalObject().getPitch(); + return platformEntity().getPitch(); } @Override public World world() { - return new BukkitWorld(literalObject().getWorld()); + return new BukkitWorld(platformEntity().getWorld()); } @Override @@ -62,22 +64,43 @@ public class BukkitEntity extends AbstractEntity { } @Override - public org.bukkit.entity.Entity literalObject() { + public org.bukkit.entity.Entity platformEntity() { return this.entity.get(); } + @Override + public Object serverEntity() { + return FastNMS.INSTANCE.method$CraftEntity$getHandle(platformEntity()); + } + @Override public Key type() { - return EntityUtils.getEntityType(literalObject()); + return EntityUtils.getEntityType(platformEntity()); } @Override public String name() { - return literalObject().getName(); + return platformEntity().getName(); } @Override public UUID uuid() { - return literalObject().getUniqueId(); + return platformEntity().getUniqueId(); + } + + @Override + public Object entityData() { + return FastNMS.INSTANCE.field$Entity$entityData(serverEntity()); + } + + @SuppressWarnings("unchecked") + @Override + public T getEntityData(EntityData data) { + return (T) FastNMS.INSTANCE.method$SynchedEntityData$get(entityData(), data.entityDataAccessor()); + } + + @Override + public void setEntityData(EntityData data, T value, boolean force) { + FastNMS.INSTANCE.method$SynchedEntityData$set(entityData(), data.entityDataAccessor(), value, force); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BaseEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BaseEntityData.java index 2b101a64f..93b8cb707 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BaseEntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BaseEntityData.java @@ -4,7 +4,7 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflect import java.util.Optional; -public class BaseEntityData extends SimpleEntityData { +public class BaseEntityData extends BukkitEntityData { public static final BaseEntityData SharedFlags = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$BYTE, (byte) 0); public static final BaseEntityData AirSupply = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$INT, 300); public static final BaseEntityData> CustomName = new BaseEntityData<>(BaseEntityData.class, EntityDataValue.Serializers$OPTIONAL_COMPONENT, Optional.empty()); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/SimpleEntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BukkitEntityData.java similarity index 74% rename from bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/SimpleEntityData.java rename to bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BukkitEntityData.java index 5cb42e2f6..2e3ee3eae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/SimpleEntityData.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/BukkitEntityData.java @@ -2,15 +2,16 @@ package net.momirealms.craftengine.bukkit.entity.data; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.core.entity.data.ClassTreeIdRegistry; +import net.momirealms.craftengine.core.entity.data.EntityData; -public class SimpleEntityData implements EntityData { +public class BukkitEntityData implements EntityData { public static final ClassTreeIdRegistry ID_REGISTRY = new ClassTreeIdRegistry(); private final int id; private final Object serializer; private final T defaultValue; private final Object entityDataAccessor; - public SimpleEntityData(Class clazz, Object serializer, T defaultValue) { + public BukkitEntityData(Class clazz, Object serializer, T defaultValue) { this.id = ID_REGISTRY.define(clazz); this.serializer = serializer; this.defaultValue = defaultValue; @@ -36,4 +37,9 @@ public class SimpleEntityData implements EntityData { public Object entityDataAccessor() { return entityDataAccessor; } + + @Override + public Object create(Object entityDataAccessor, Object value) { + return EntityDataValue.create(entityDataAccessor, value); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java deleted file mode 100644 index 0574a93f9..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityData.java +++ /dev/null @@ -1,40 +0,0 @@ -package net.momirealms.craftengine.bukkit.entity.data; - -import net.momirealms.craftengine.bukkit.nms.FastNMS; - -import java.util.List; - -public interface EntityData { - - Object serializer(); - - int id(); - - T defaultValue(); - - Object entityDataAccessor(); - - default Object createEntityDataIfNotDefaultValue(T value) { - if (defaultValue().equals(value)) return null; - return EntityDataValue.create(id(), serializer(), entityDataAccessor(), value); - } - - default void addEntityDataIfNotDefaultValue(T value, List list) { - if (!defaultValue().equals(value)) { - list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value)); - } - } - - default void addEntityData(T value, List list) { - list.add(EntityDataValue.create(id(), serializer(), entityDataAccessor(), value)); - } - - @SuppressWarnings("unchecked") - default T get(Object entityData) { - return (T) FastNMS.INSTANCE.method$SynchedEntityData$get(entityData, entityDataAccessor()); - } - - static EntityData of(Class clazz, Object serializer, T defaultValue) { - return new SimpleEntityData<>(clazz, serializer, defaultValue); - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java index 30d191d09..39e6f1950 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/entity/data/EntityDataValue.java @@ -99,7 +99,7 @@ public class EntityDataValue { throw new IllegalAccessError("Utility class"); } - public static Object create(int id, Object serializer, Object entityDataAccessor, Object value) { + public static Object create(Object entityDataAccessor, Object value) { return FastNMS.INSTANCE.method$SynchedEntityData$DataValue$create(entityDataAccessor, value); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java index 03aac1937..0545ee0b4 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/TotemAnimationCommand.java @@ -3,7 +3,10 @@ package net.momirealms.craftengine.bukkit.plugin.command.feature; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; import net.momirealms.craftengine.bukkit.item.ComponentTypes; +import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MSoundEvents; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.KeyUtils; import net.momirealms.craftengine.bukkit.util.PlayerUtils; @@ -34,11 +37,13 @@ import org.incendo.cloud.parser.standard.FloatParser; import org.incendo.cloud.suggestion.Suggestion; import org.incendo.cloud.suggestion.SuggestionProvider; +import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; public class TotemAnimationCommand extends BukkitCommandFeature { + public static final Object FIX_TOTEM_SOUND_PACKET = FastNMS.INSTANCE.constructor$ClientboundSoundPacket(FastNMS.INSTANCE.method$Holder$direct(MSoundEvents.TOTEM_USE), CoreReflections.instance$SoundSource$MUSIC, 0, Integer.MIN_VALUE, 0, 0, 0, 0); public TotemAnimationCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { super(commandManager, plugin); @@ -85,17 +90,21 @@ public class TotemAnimationCommand extends BukkitCommandFeature { } boolean removeSound = context.flags().hasFlag("no-sound"); MultiplePlayerSelector selector = context.get("players"); - for (Player player : selector.values()) { + Collection players = selector.values(); + for (Player player : players) { BukkitServerPlayer serverPlayer = BukkitAdaptors.adapt(player); Item item = customItem.buildItem(serverPlayer); if (VersionHelper.isOrAbove1_21_2()) { item.setJavaComponent(ComponentTypes.DEATH_PROTECTION, Map.of()); } - // TODO 存在第一次进服 未正确移除图腾声音的问题 PlayerUtils.sendTotemAnimation(serverPlayer, item, soundData, removeSound); } - // TODO 消息提示 + if (players.size() == 1) { + handleFeedback(context, MessageConstants.COMMAND_TOTEM_SUCCESS_SINGLE, Component.text(namespacedKey.toString()), Component.text(players.iterator().next().getName())); + } else if (players.size() > 1) { + handleFeedback(context, MessageConstants.COMMAND_TOTEM_SUCCESS_MULTIPLE, Component.text(namespacedKey.toString()), Component.text(players.size())); + } }); } 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 e0f6210a7..ba59dcb7b 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 @@ -36,6 +36,7 @@ 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.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.bukkit.plugin.command.feature.TotemAnimationCommand; import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor; import net.momirealms.craftengine.bukkit.plugin.network.handler.*; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20; @@ -423,6 +424,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes player.getScheduler().runAtFixedRate(plugin.javaPlugin(), (t) -> user.tick(), () -> {}, 1, 1); } + user.sendPacket(TotemAnimationCommand.FIX_TOTEM_SOUND_PACKET, false); } } @@ -2385,7 +2387,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - @SuppressWarnings("all") + @SuppressWarnings({"deprecation", "all"}) public HoverEvent.ShowItem replaceShowItem(HoverEvent.ShowItem showItem, BukkitServerPlayer player) { Object nmsItemStack; if (VersionHelper.COMPONENT_RELEASE) { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/leaves/LeavesReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/leaves/LeavesReflections.java index dd5522890..10de64942 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/leaves/LeavesReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/leaves/LeavesReflections.java @@ -8,10 +8,13 @@ package net.momirealms.craftengine.bukkit.plugin.reflection.leaves; //import java.lang.reflect.Field; //import java.util.Optional; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ReflectionUtils; +import net.momirealms.craftengine.core.util.VersionHelper; import java.lang.reflect.Field; import java.util.List; +import java.util.Optional; // TODO API 太新了需要1.21.8,目前先采用其他方式解决假人问题 public final class LeavesReflections { @@ -36,14 +39,21 @@ public final class LeavesReflections { // public static final Field field$BotRemoveEvent$handlers = Optional.ofNullable(clazz$BotRemoveEvent) // .map(it -> ReflectionUtils.getDeclaredField(it, HandlerList.class, 0)) // .orElse(null); - - - public static final Class clazz$ServerBot = ReflectionUtils.getClazz("org.leavesmc.leaves.bot.ServerBot"); +// +// +// public static final Class clazz$ServerBot = ReflectionUtils.getClazz("org.leavesmc.leaves.bot.ServerBot"); // 注入BotList来实现全版本的监听 - public static final Class clazz$BotList = ReflectionUtils.getClazz("org.leavesmc.leaves.bot.BotList"); + public static final Class clazz$BotList = MiscUtils.requireNonNullIf( + ReflectionUtils.getClazz("org.leavesmc.leaves.bot.BotList"), + VersionHelper.isLeaves() + ); - public static final Field field$BotList$INSTANCE = ReflectionUtils.getDeclaredField(clazz$BotList, clazz$BotList, 0); + public static final Field field$BotList$INSTANCE = Optional.ofNullable(clazz$BotList) + .map(c -> ReflectionUtils.getDeclaredField(c, c, 0)) + .orElse(null); - public static final Field field$BotList$bots = ReflectionUtils.getDeclaredField(clazz$BotList, List.class, 0); + public static final Field field$BotList$bots = Optional.ofNullable(clazz$BotList) + .map(c -> ReflectionUtils.getDeclaredField(c, List.class, 0)) + .orElse(null); } 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 747dde390..e02250d2c 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 @@ -5,22 +5,15 @@ import net.momirealms.craftengine.bukkit.nms.FastNMS; public final class MSoundEvents { private MSoundEvents() {} - public static final Object EMPTY; - public static final Object TRIDENT_RIPTIDE_1; - public static final Object TRIDENT_RIPTIDE_2; - public static final Object TRIDENT_RIPTIDE_3; - public static final Object TRIDENT_THROW; + public static final Object EMPTY = getById("intentionally_empty"); + public static final Object TRIDENT_RIPTIDE_1 = getById("item.trident_riptide_1"); + public static final Object TRIDENT_RIPTIDE_2 = getById("item.trident_riptide_2"); + public static final Object TRIDENT_RIPTIDE_3 = getById("item.trident.riptide_3"); + public static final Object TRIDENT_THROW = getById("item.trident.throw"); + public static final Object TOTEM_USE = getById("item.totem.use"); private static Object getById(String id) { Object rl = FastNMS.INSTANCE.method$ResourceLocation$fromNamespaceAndPath("minecraft", id); return FastNMS.INSTANCE.method$Registry$getValue(MBuiltInRegistries.SOUND_EVENT, rl); } - - static { - 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/user/BukkitServerPlayer.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/user/BukkitServerPlayer.java index 65eaf3b2f..7e4467372 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 @@ -8,15 +8,13 @@ import io.netty.channel.ChannelHandler; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.entity.BlockEntityHolder; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.*; +import net.momirealms.craftengine.core.entity.data.EntityData; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.gui.CraftEngineGUIHolder; import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MMobEffects; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.advancement.AdvancementType; @@ -943,10 +941,15 @@ public class BukkitServerPlayer extends Player { } @Override - public org.bukkit.entity.Player literalObject() { + public org.bukkit.entity.Player platformEntity() { return platformPlayer(); } + @Override + public Object serverEntity() { + return serverPlayer(); + } + @Override public Map entityPacketHandlers() { return this.entityTypeView; @@ -1143,4 +1146,20 @@ public class BukkitServerPlayer extends Player { DamageType type = Registry.DAMAGE_TYPE.get(KeyUtils.toNamespacedKey(damageType)); this.platformPlayer().damage(amount, DamageSource.builder(type != null ? type : DamageType.GENERIC).build()); } + + @Override + public Object entityData() { + return FastNMS.INSTANCE.field$Entity$entityData(serverEntity()); + } + + @SuppressWarnings("unchecked") + @Override + public T getEntityData(EntityData data) { + return (T) FastNMS.INSTANCE.method$SynchedEntityData$get(entityData(), data.entityDataAccessor()); + } + + @Override + public void setEntityData(EntityData data, T value, boolean force) { + FastNMS.INSTANCE.method$SynchedEntityData$set(entityData(), data.entityDataAccessor(), value, force); + } } diff --git a/common-files/src/main/resources/translations/en.yml b/common-files/src/main/resources/translations/en.yml index 745d94e46..e7a1325d6 100644 --- a/common-files/src/main/resources/translations/en.yml +++ b/common-files/src/main/resources/translations/en.yml @@ -54,6 +54,8 @@ command.search_usage.not_found: "No usage found for this item" command.search_recipe.no_item: "Please hold an item before running this command" command.search_usage.no_item: "Please hold an item before running this command" command.totem_animation.failure.not_totem: "Item '' is not minecraft:totem_of_undying" +commands.totem_animation.success.single: "Played totem animation to " +commands.totem_animation.success.multiple: "Played totem animation to players" command.resource.enable.success: "Enabled resource . Run /ce reload all to apply changes" command.resource.enable.failure.unknown: "Unknown resource " command.resource.disable.success: "Disabled resource . Run /ce reload all to apply changes" diff --git a/common-files/src/main/resources/translations/zh_cn.yml b/common-files/src/main/resources/translations/zh_cn.yml index 5549ef095..4298f19fa 100644 --- a/common-files/src/main/resources/translations/zh_cn.yml +++ b/common-files/src/main/resources/translations/zh_cn.yml @@ -54,6 +54,8 @@ command.search_usage.not_found: "找不到此物品的用途" command.search_recipe.no_item: "请手持物品后再执行此命令" command.search_usage.no_item: "请手持物品后再执行此命令" command.totem_animation.failure.not_totem: "'' 不是 totem_of_undying 类型" +commands.totem_animation.success.single: "已将图腾动画播放给" +commands.totem_animation.success.multiple: "已将图腾动画播放给名玩家" command.resource.enable.success: "已启用 . 执行 /ce reload all 以应用更改" command.resource.enable.failure.unknown: "未知资源 " command.resource.disable.success: "已禁用 . 执行 /ce reload all 以应用更改" diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java index aac181c4b..ba2a81d73 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/Entity.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.entity; +import net.momirealms.craftengine.core.entity.data.EntityData; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.world.World; @@ -30,9 +31,21 @@ public interface Entity { Direction getDirection(); - Object literalObject(); + Object platformEntity(); + + Object serverEntity(); String name(); UUID uuid(); + + Object entityData(); + + T getEntityData(EntityData entityData); + + default void setEntityData(EntityData data, T value) { + setEntityData(data, value, false); + } + + void setEntityData(EntityData data, T value, boolean force); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/entity/data/EntityData.java b/core/src/main/java/net/momirealms/craftengine/core/entity/data/EntityData.java new file mode 100644 index 000000000..1351831e6 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/entity/data/EntityData.java @@ -0,0 +1,35 @@ +package net.momirealms.craftengine.core.entity.data; + +import java.util.List; + +public interface EntityData { + + Object serializer(); + + int id(); + + T defaultValue(); + + Object entityDataAccessor(); + + Object create(Object entityDataAccessor, Object value); + + default Object createEntityDataIfNotDefaultValue(T value) { + if (defaultValue().equals(value)) return null; + return create(entityDataAccessor(), value); + } + + default Object createEntityData(Object value) { + return create(entityDataAccessor(), value); + } + + default void addEntityDataIfNotDefaultValue(T value, List list) { + if (!defaultValue().equals(value)) { + list.add(create(entityDataAccessor(), value)); + } + } + + default void addEntityData(T value, List list) { + list.add(create(entityDataAccessor(), value)); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java index 274e7cf0c..91c6db67b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/locale/MessageConstants.java @@ -30,4 +30,6 @@ public interface MessageConstants { TranslatableComponent.Builder COMMAND_UPLOAD_ON_PROGRESS = Component.translatable().key("command.upload.on_progress"); TranslatableComponent.Builder COMMAND_SEND_RESOURCE_PACK_SUCCESS_SINGLE = Component.translatable().key("command.send_resource_pack.success.single"); TranslatableComponent.Builder COMMAND_SEND_RESOURCE_PACK_SUCCESS_MULTIPLE = Component.translatable().key("command.send_resource_pack.success.multiple"); + TranslatableComponent.Builder COMMAND_TOTEM_SUCCESS_SINGLE = Component.translatable().key("commands.totem_animation.success.single"); + TranslatableComponent.Builder COMMAND_TOTEM_SUCCESS_MULTIPLE = Component.translatable().key("commands.totem_animation.success.multiple"); } diff --git a/gradle.properties b/gradle.properties index c7aaf559b..7e597d9d3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.jvmargs=-Xmx1G # Rule: [major update].[feature update].[bug fix] project_version=0.0.63.9 config_version=47 -lang_version=32 +lang_version=33 project_group=net.momirealms latest_supported_version=1.21.10 @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=0.20 -nms_helper_version=1.0.101 +nms_helper_version=1.0.102 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5 From 3906a55b2d2fcb2b850c4860a28b4a91b1ceec9c Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 4 Oct 2025 22:17:31 +0800 Subject: [PATCH 112/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9D=91=E6=B0=91?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E7=89=A9=E5=93=81=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../command/feature/OverrideGiveCommand.java | 91 ------------ .../plugin/network/BukkitNetworkManager.java | 131 +++++++++++++++++- .../bukkit/plugin/network/PacketIds.java | 2 + .../plugin/network/id/PacketIds1_20.java | 6 +- .../plugin/network/id/PacketIds1_20_5.java | 5 + .../reflection/minecraft/CoreReflections.java | 7 + .../minecraft/NetworkReflections.java | 21 +++ .../core/item/trade/MerchantOffer.java | 87 ++++++++++++ gradle.properties | 2 +- 9 files changed, 255 insertions(+), 97 deletions(-) delete mode 100644 bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/OverrideGiveCommand.java create mode 100644 core/src/main/java/net/momirealms/craftengine/core/item/trade/MerchantOffer.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/OverrideGiveCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/OverrideGiveCommand.java deleted file mode 100644 index 4fbf77a78..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/OverrideGiveCommand.java +++ /dev/null @@ -1,91 +0,0 @@ -//package net.momirealms.craftengine.bukkit.plugin.command.feature; -// -//import net.kyori.adventure.text.Component; -//import net.momirealms.craftengine.bukkit.api.BukkitAdaptors; -//import net.momirealms.craftengine.bukkit.item.BukkitItemManager; -//import net.momirealms.craftengine.bukkit.plugin.command.BukkitCommandFeature; -//import net.momirealms.craftengine.bukkit.util.PlayerUtils; -//import net.momirealms.craftengine.core.item.Item; -//import net.momirealms.craftengine.core.plugin.CraftEngine; -//import net.momirealms.craftengine.core.plugin.command.CraftEngineCommandManager; -//import net.momirealms.craftengine.core.plugin.locale.MessageConstants; -//import net.momirealms.craftengine.core.util.Key; -//import org.bukkit.NamespacedKey; -//import org.bukkit.command.CommandSender; -//import org.bukkit.entity.Player; -//import org.bukkit.inventory.ItemStack; -//import org.checkerframework.checker.nullness.qual.NonNull; -//import org.incendo.cloud.Command; -//import org.incendo.cloud.bukkit.data.MultiplePlayerSelector; -//import org.incendo.cloud.bukkit.parser.NamespacedKeyParser; -//import org.incendo.cloud.bukkit.parser.selector.MultiplePlayerSelectorParser; -//import org.incendo.cloud.context.CommandContext; -//import org.incendo.cloud.context.CommandInput; -//import org.incendo.cloud.parser.standard.IntegerParser; -//import org.incendo.cloud.suggestion.Suggestion; -//import org.incendo.cloud.suggestion.SuggestionProvider; -// -//import java.util.Collection; -//import java.util.concurrent.CompletableFuture; -// -//public class OverrideGiveCommand extends BukkitCommandFeature { -// -// public OverrideGiveCommand(CraftEngineCommandManager commandManager, CraftEngine plugin) { -// super(commandManager, plugin); -// } -// -// @Override -// public Command.Builder assembleCommand(org.incendo.cloud.CommandManager manager, Command.Builder builder) { -// return builder -// .required("player", MultiplePlayerSelectorParser.multiplePlayerSelectorParser(true)) -// .required("id", NamespacedKeyParser.namespacedKeyComponent().suggestionProvider(new SuggestionProvider<>() { -// @Override -// public @NonNull CompletableFuture> suggestionsFuture(@NonNull CommandContext context, @NonNull CommandInput input) { -// return CompletableFuture.completedFuture(plugin().itemManager().cachedAllItemSuggestions()); -// } -// })) -// .optional("amount", IntegerParser.integerParser(1, 6400)) -// .handler(context -> { -// MultiplePlayerSelector selector = context.get("player"); -// int amount = context.getOrDefault("amount", 1); -// NamespacedKey namespacedKey = context.get("id"); -// Key itemId = Key.of(namespacedKey.namespace(), namespacedKey.value()); -// Collection players = selector.values(); -// -// Component anyItemDisplayName = null; -// -// for (Player player : players) { -// Item builtItem = BukkitItemManager.instance().createWrappedItem(itemId, BukkitAdaptors.adapt(player)); -// if (builtItem == null) { -// return; -// } -// int maxStack = builtItem.maxStackSize(); -// anyItemDisplayName = builtItem.hoverNameComponent() -// .orElseGet(() -> { -// if (builtItem.isCustomItem()) { -// return Component.text(itemId.asString()); -// } else { -// return Component.translatable("item.minecraft." + itemId.value()); -// } -// }); -// -// if (amount > maxStack * 100) { -// plugin().senderFactory().wrap(context.sender()).sendMessage(Component.translatable("commands.give.failed.toomanyitems", Component.text(maxStack * 100), anyItemDisplayName); -// return; -// } -// -// PlayerUtils.giveItem(player, amount, builtItem); -// } -// if (players.size() == 1) { -// plugin().senderFactory().wrap(context.sender()).sendMessage(Component.translatable("commands.give.success.single", Component.text(amount), anyItemDisplayName, )); -// } else if (players.size() > 1) { -// handleFeedback(context, MessageConstants.COMMAND_ITEM_GIVE_SUCCESS_MULTIPLE, Component.text(amount), Component.text(itemId.toString()), Component.text(players.size())); -// } -// }); -// } -// -// @Override -// public String getFeatureID() { -// return "override_minecraft_give"; -// } -//} 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 ba59dcb7b..6cae15d41 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 @@ -58,6 +58,7 @@ import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; 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.block.entity.render.DynamicBlockEntityRenderer; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; @@ -68,6 +69,7 @@ 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.item.trade.MerchantOffer; import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -354,6 +356,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes registerC2SGamePacketListener(new ContainerClick1_20(), VersionHelper.isOrAbove1_21_5() ? -1 : this.packetIds.serverboundContainerClickPacket(), "ServerboundContainerClickPacket"); registerC2SGamePacketListener(new InteractEntityListener(), this.packetIds.serverboundInteractPacket(), "ServerboundInteractPacket"); registerC2SGamePacketListener(new CustomPayloadListener1_20(), VersionHelper.isOrAbove1_20_2() ? -1 : this.packetIds.serverboundCustomPayloadPacket(), "ServerboundCustomPayloadPacket"); + registerS2CGamePacketListener(VersionHelper.isOrAbove1_20_5() ? new MerchantOffersListener1_20_5() : new MerchantOffersListener1_20(), this.packetIds.clientBoundMerchantOffersPacket(), "ClientboundMerchantOffersPacket"); registerS2CGamePacketListener(new AddEntityListener(RegistryUtils.currentEntityTypeRegistrySize()), this.packetIds.clientboundAddEntityPacket(), "ClientboundAddEntityPacket"); registerS2CGamePacketListener( VersionHelper.isOrAbove1_20_3() ? @@ -2167,7 +2170,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes float zDist = buf.readFloat(); float maxSpeed = buf.readFloat(); int count = buf.readInt(); - Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); + Object option = FastNMS.INSTANCE.method$StreamDecoder$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf)); if (option == null) return; if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); @@ -2189,7 +2192,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes buf.writeFloat(zDist); buf.writeFloat(maxSpeed); buf.writeInt(count); - FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); + FastNMS.INSTANCE.method$StreamEncoder$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf), remappedOption); } } @@ -2214,7 +2217,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes float zDist = buf.readFloat(); float maxSpeed = buf.readFloat(); int count = buf.readInt(); - Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); + Object option = FastNMS.INSTANCE.method$StreamDecoder$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf)); if (option == null) return; if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); @@ -2235,7 +2238,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes buf.writeFloat(zDist); buf.writeFloat(maxSpeed); buf.writeInt(count); - FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); + FastNMS.INSTANCE.method$StreamEncoder$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf), remappedOption); } } @@ -3803,4 +3806,124 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } } + + public static class MerchantOffersListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readContainerId(); + BukkitItemManager manager = BukkitItemManager.instance(); + List> merchantOffers = buf.readCollection(ArrayList::new, byteBuf -> { + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(byteBuf); + ItemStack cost1 = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + ItemStack result = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + ItemStack cost2 = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + boolean outOfStock = byteBuf.readBoolean(); + int uses = byteBuf.readInt(); + int maxUses = byteBuf.readInt(); + int xp = byteBuf.readInt(); + int specialPrice = byteBuf.readInt(); + float priceMultiplier = byteBuf.readFloat(); + int demand = byteBuf.readInt(); + return new MerchantOffer<>(manager.wrap(cost1), Optional.of(manager.wrap(cost2)), manager.wrap(result), outOfStock, uses, maxUses, xp, specialPrice, priceMultiplier, demand); + }); + for (MerchantOffer offer : merchantOffers) { + offer.applyClientboundData(item -> manager.s2c(item, serverPlayer)); + } + int villagerLevel = buf.readVarInt(); + int villagerXp = buf.readVarInt(); + boolean showProgress = buf.readBoolean(); + boolean canRestock = buf.readBoolean(); + + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeCollection(merchantOffers, (byteBuf, offer) -> { + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(byteBuf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(friendlyBuf, offer.cost1().getItem()); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(friendlyBuf, offer.result().getItem()); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(friendlyBuf, offer.cost2().get().getItem()); + byteBuf.writeBoolean(offer.outOfStock()); + byteBuf.writeInt(offer.uses()); + byteBuf.writeInt(offer.maxUses()); + byteBuf.writeInt(offer.xp()); + byteBuf.writeInt(offer.specialPrice()); + byteBuf.writeFloat(offer.priceMultiplier()); + byteBuf.writeInt(offer.demand()); + }); + + buf.writeVarInt(villagerLevel); + buf.writeVarInt(villagerXp); + buf.writeBoolean(showProgress); + buf.writeBoolean(canRestock); + } + } + + public static class MerchantOffersListener1_20_5 implements ByteBufferPacketListener { + + @SuppressWarnings("unchecked") + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readContainerId(); + BukkitItemManager manager = BukkitItemManager.instance(); + List> merchantOffers = buf.readCollection(ArrayList::new, byteBuf -> { + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(byteBuf); + ItemStack cost1 = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$ItemCost$itemStack(FastNMS.INSTANCE.method$StreamDecoder$decode(NetworkReflections.instance$ItemCost$STREAM_CODEC, friendlyBuf))); + ItemStack result = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional cost2 = ((Optional) FastNMS.INSTANCE.method$StreamDecoder$decode(NetworkReflections.instance$ItemCost$OPTIONAL_STREAM_CODEC, friendlyBuf)) + .map(cost -> FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(FastNMS.INSTANCE.field$ItemCost$itemStack(cost))); + boolean outOfStock = byteBuf.readBoolean(); + int uses = byteBuf.readInt(); + int maxUses = byteBuf.readInt(); + int xp = byteBuf.readInt(); + int specialPrice = byteBuf.readInt(); + float priceMultiplier = byteBuf.readFloat(); + int demand = byteBuf.readInt(); + return new MerchantOffer<>(manager.wrap(cost1), cost2.map(manager::wrap), manager.wrap(result), outOfStock, uses, maxUses, xp, specialPrice, priceMultiplier, demand); + }); + for (MerchantOffer offer : merchantOffers) { + offer.applyClientboundData(item -> manager.s2c(item, serverPlayer)); + } + int villagerLevel = buf.readVarInt(); + int villagerXp = buf.readVarInt(); + boolean showProgress = buf.readBoolean(); + boolean canRestock = buf.readBoolean(); + + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeCollection(merchantOffers, (byteBuf, offer) -> { + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(byteBuf); + FastNMS.INSTANCE.method$StreamEncoder$encode(NetworkReflections.instance$ItemCost$STREAM_CODEC, friendlyBuf, itemStackToItemCost(offer.cost1().getLiteralObject(), offer.cost1().count())); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(friendlyBuf, offer.result().getItem()); + FastNMS.INSTANCE.method$StreamEncoder$encode(NetworkReflections.instance$ItemCost$OPTIONAL_STREAM_CODEC, friendlyBuf, offer.cost2().map(it -> itemStackToItemCost(it.getLiteralObject(), it.count()))); + byteBuf.writeBoolean(offer.outOfStock()); + byteBuf.writeInt(offer.uses()); + byteBuf.writeInt(offer.maxUses()); + byteBuf.writeInt(offer.xp()); + byteBuf.writeInt(offer.specialPrice()); + byteBuf.writeFloat(offer.priceMultiplier()); + byteBuf.writeInt(offer.demand()); + }); + + buf.writeVarInt(villagerLevel); + buf.writeVarInt(villagerXp); + buf.writeBoolean(showProgress); + buf.writeBoolean(canRestock); + } + + private Object itemStackToItemCost(Object itemStack, int count) { + return FastNMS.INSTANCE.constructor$ItemCost( + FastNMS.INSTANCE.method$Item$builtInRegistryHolder(FastNMS.INSTANCE.method$ItemStack$getItem(itemStack)), + count, + FastNMS.INSTANCE.method$DataComponentExactPredicate$allOf(FastNMS.INSTANCE.method$ItemStack$getComponents(itemStack)) + ); + } + } } 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 b8b0e9cc8..ad0d6b86e 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 @@ -60,6 +60,8 @@ public interface PacketIds { int clientboundUpdateAdvancementsPacket(); + int clientBoundMerchantOffersPacket(); + int serverboundContainerClickPacket(); int serverboundSetCreativeModeSlotPacket(); 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 8b33c8fef..ed5beaa0c 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 @@ -161,6 +161,11 @@ public class PacketIds1_20 implements PacketIds { return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundBlockEventPacket, PacketFlow.CLIENTBOUND); } + @Override + public int clientBoundMerchantOffersPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundMerchantOffersPacket, PacketFlow.CLIENTBOUND); + } + @Override public int serverboundContainerClickPacket() { return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundContainerClickPacket, PacketFlow.SERVERBOUND); @@ -171,7 +176,6 @@ public class PacketIds1_20 implements PacketIds { return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket, PacketFlow.SERVERBOUND); } - @Override public int serverboundInteractPacket() { return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundInteractPacket, PacketFlow.SERVERBOUND); 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 9aea4a3df..e6240cb1d 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 @@ -160,6 +160,11 @@ public class PacketIds1_20_5 implements PacketIds { return PlayPacketIdHelper.byName("minecraft:forget_level_chunk", PacketFlow.CLIENTBOUND); } + @Override + public int clientBoundMerchantOffersPacket() { + return PlayPacketIdHelper.byName("minecraft:merchant_offers", PacketFlow.CLIENTBOUND); + } + @Override public int serverboundContainerClickPacket() { return PlayPacketIdHelper.byName("minecraft:container_click", PacketFlow.SERVERBOUND); 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 6cc1e3c7d..736271cfa 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 @@ -4463,4 +4463,11 @@ public final class CoreReflections { public static final Field field$EnumProperty$values = requireNonNull( ReflectionUtils.getDeclaredField(clazz$EnumProperty, VersionHelper.isOrAbove1_21_2() ? List.class : ImmutableSet.class, 0) ); + + public static final Class clazz$ItemCost = MiscUtils.requireNonNullIf( + BukkitReflectionUtils.findReobfOrMojmapClass( + "world.item.trading.ItemCost", + "world.item.trading.ItemCost" + ), VersionHelper.isOrAbove1_20_5() + ); } 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 e36fac81c..e6513a3ed 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 @@ -1692,4 +1692,25 @@ public final class NetworkReflections { CoreReflections.clazz$SoundSource ) ); + + public static final Class clazz$ClientboundMerchantOffersPacket = requireNonNull( + BukkitReflectionUtils.findReobfOrMojmapClass( + "network.protocol.game.PacketPlayOutOpenWindowMerchant", + "network.protocol.game.ClientboundMerchantOffersPacket" + ) + ); + + public static final Object instance$ItemCost$STREAM_CODEC; + public static final Object instance$ItemCost$OPTIONAL_STREAM_CODEC; + + static { + try { + instance$ItemCost$STREAM_CODEC = !VersionHelper.isOrAbove1_20_5() ? null : + ReflectionUtils.getDeclaredField(CoreReflections.clazz$ItemCost, clazz$StreamCodec, 0).get(null); + instance$ItemCost$OPTIONAL_STREAM_CODEC = !VersionHelper.isOrAbove1_20_5() ? null : + ReflectionUtils.getDeclaredField(CoreReflections.clazz$ItemCost, clazz$StreamCodec, 1).get(null); + } catch (ReflectiveOperationException e) { + throw new ReflectionInitException("Failed to initialize ItemCost$STREAM_CODEC", e); + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/trade/MerchantOffer.java b/core/src/main/java/net/momirealms/craftengine/core/item/trade/MerchantOffer.java new file mode 100644 index 000000000..4fa2f74b7 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/trade/MerchantOffer.java @@ -0,0 +1,87 @@ +package net.momirealms.craftengine.core.item.trade; + +import net.momirealms.craftengine.core.item.Item; + +import java.util.Optional; +import java.util.function.Function; + +public class MerchantOffer { + private Item cost1; + private Optional> cost2; + private Item result; + private final int uses; + private final int maxUses; + private final int specialPrice; + private final int xp; + private final float priceMultiplier; + private final int demand; + private final boolean outOfStock; + + public MerchantOffer(Item cost1, + Optional> cost2, + Item result, + boolean outOfStock, + int uses, + int maxUses, + int xp, + int specialPrice, + float priceMultiplier, + int demand) { + this.cost1 = cost1; + this.cost2 = cost2; + this.result = result; + this.outOfStock = outOfStock; + this.uses = uses; + this.maxUses = maxUses; + this.specialPrice = specialPrice; + this.xp = xp; + this.priceMultiplier = priceMultiplier; + this.demand = demand; + } + + public void applyClientboundData(Function, Item> function) { + this.cost1 = function.apply(this.cost1); + this.cost2 = this.cost2.map(function); + this.result = function.apply(this.result); + } + + public Item cost1() { + return cost1; + } + + public Optional> cost2() { + return cost2; + } + + public Item result() { + return result; + } + + public int uses() { + return uses; + } + + public int maxUses() { + return maxUses; + } + + public int specialPrice() { + return specialPrice; + } + + public int xp() { + return xp; + } + + public float priceMultiplier() { + return priceMultiplier; + } + + public int demand() { + return demand; + } + + public boolean outOfStock() { + return outOfStock; + } +} diff --git a/gradle.properties b/gradle.properties index a606d91b8..352edc9f8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=1.0.2 -nms_helper_version=1.0.102 +nms_helper_version=1.0.103 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5 From baa255736dfabadf522e6ad237de05532e3022b6 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 4 Oct 2025 22:23:49 +0800 Subject: [PATCH 113/125] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 352edc9f8..153a6411f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.9 +project_version=0.0.63.10 config_version=47 lang_version=33 project_group=net.momirealms From 1ee80df8443774304f8ffd1145600fd651a40471 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 15:58:55 +0800 Subject: [PATCH 114/125] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=B8=80=E4=B8=8Bsta?= =?UTF-8?q?te=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/behavior/FenceBlockBehavior.java | 7 +- .../behavior/StrippableBlockBehavior.java | 18 +- .../bukkit/item/behavior/AxeItemBehavior.java | 17 +- .../plugin/network/BukkitNetworkManager.java | 1 - .../plugin/user/BukkitServerPlayer.java | 7 +- .../core/block/BlockStateHolder.java | 131 ------------- .../core/block/ImmutableBlockState.java | 178 +++++++++++++++--- .../block/properties/BooleanProperty.java | 10 + .../core/block/properties/EnumProperty.java | 5 + .../block/properties/IntegerProperty.java | 11 ++ .../core/block/properties/Property.java | 3 + .../core/block/properties/StringProperty.java | 21 ++- 12 files changed, 224 insertions(+), 185 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java index 0a4de1cbf..4adb6c62e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/FenceBlockBehavior.java @@ -6,7 +6,10 @@ import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MFluids; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistries; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MTagKeys; import net.momirealms.craftengine.bukkit.util.*; -import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.BlockBehavior; +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.BlockBehaviorFactory; import net.momirealms.craftengine.core.block.properties.BooleanProperty; import net.momirealms.craftengine.core.entity.player.InteractionHand; @@ -112,7 +115,7 @@ public class FenceBlockBehavior extends BukkitBlockBehavior { public Object updateShape(Object thisBlock, Object[] args, Callable superMethod) throws Exception { Optional optionalState = BlockStateUtils.getOptionalCustomBlockState(args[0]); BooleanProperty waterlogged = (BooleanProperty) optionalState - .map(BlockStateHolder::owner) + .map(ImmutableBlockState::owner) .map(Holder::value) .map(block -> block.getProperty("waterlogged")) .orElse(null); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java index 00aff9787..a1b243ee9 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java @@ -2,31 +2,39 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.core.block.BlockBehavior; import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; -import net.momirealms.craftengine.core.util.Key; +import net.momirealms.craftengine.core.block.parser.BlockStateParser; +import net.momirealms.craftengine.core.util.LazyReference; import net.momirealms.craftengine.core.util.ResourceConfigUtils; import java.util.Map; public class StrippableBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); - private final Key stripped; + private final String stripped; + private final LazyReference lazyState; - public StrippableBlockBehavior(CustomBlock block, Key stripped) { + public StrippableBlockBehavior(CustomBlock block, String stripped) { super(block); this.stripped = stripped; + this.lazyState = LazyReference.lazyReference(() -> BlockStateParser.deserialize(this.stripped)); } - public Key stripped() { + public String stripped() { return this.stripped; } + public ImmutableBlockState strippedState() { + return this.lazyState.get(); + } + public static class Factory implements BlockBehaviorFactory { @Override public BlockBehavior create(CustomBlock block, Map arguments) { String stripped = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("stripped"), "warning.config.block.behavior.strippable.missing_stripped"); - return new StrippableBlockBehavior(block, Key.of(stripped)); + return new StrippableBlockBehavior(block, stripped); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index 2cca3f5ae..882ba4be5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -1,13 +1,12 @@ package net.momirealms.craftengine.bukkit.item.behavior; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.block.behavior.StrippableBlockBehavior; 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.util.*; import net.momirealms.craftengine.bukkit.world.BukkitExistingBlock; -import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.entity.player.InteractionHand; @@ -25,7 +24,6 @@ import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.craftengine.core.world.BlockPos; import net.momirealms.craftengine.core.world.Vec3d; -import net.momirealms.sparrow.nbt.CompoundTag; import org.bukkit.GameEvent; import org.bukkit.Material; import org.bukkit.Statistic; @@ -66,22 +64,21 @@ public class AxeItemBehavior extends ItemBehavior { ImmutableBlockState customState = optionalCustomState.get(); Optional behaviorOptional = customState.behavior().getAs(StrippableBlockBehavior.class); if (behaviorOptional.isEmpty()) return InteractionResult.PASS; - Key stripped = behaviorOptional.get().stripped(); Item offHandItem = player != null ? (Item) player.getItemInHand(InteractionHand.OFF_HAND) : BukkitItemManager.instance().uniqueEmptyItem().item(); // is using a shield if (context.getHand() == InteractionHand.MAIN_HAND && !ItemUtils.isEmpty(offHandItem) && canBlockAttack(offHandItem) && player != null && !player.isSecondaryUseActive()) { return InteractionResult.PASS; } - Optional optionalNewCustomBlock = BukkitBlockManager.instance().blockById(stripped); - if (optionalNewCustomBlock.isEmpty()) { - CraftEngine.instance().logger().warn("stripped block " + stripped + " does not exist"); + ImmutableBlockState newState = behaviorOptional.get().strippedState(); + if (newState == null) { + CraftEngine.instance().logger().warn("stripped block " + behaviorOptional.get().stripped() + " does not exist"); return InteractionResult.FAIL; } - CustomBlock newCustomBlock = optionalNewCustomBlock.get(); - CompoundTag compoundTag = customState.propertiesNbt(); - ImmutableBlockState newState = newCustomBlock.getBlockState(compoundTag); + BlockStateWrapper + + newState = newState.with(customState.propertiesNbt()); BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlockAt(context.getClickedPos()); org.bukkit.entity.Player bukkitPlayer = null; if (player != 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 6cae15d41..25dbd4704 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 @@ -58,7 +58,6 @@ import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; 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.block.entity.render.DynamicBlockEntityRenderer; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.font.FontManager; import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; 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 7e4467372..3b5ca6675 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 @@ -8,19 +8,22 @@ import io.netty.channel.ChannelHandler; import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; import net.momirealms.craftengine.bukkit.block.entity.BlockEntityHolder; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.*; -import net.momirealms.craftengine.core.entity.data.EntityData; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.gui.CraftEngineGUIHolder; import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MAttributeHolders; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MMobEffects; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; import net.momirealms.craftengine.bukkit.util.*; import net.momirealms.craftengine.bukkit.world.BukkitWorld; import net.momirealms.craftengine.core.advancement.AdvancementType; import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.entity.BlockEntity; +import net.momirealms.craftengine.core.entity.data.EntityData; import net.momirealms.craftengine.core.entity.player.GameMode; import net.momirealms.craftengine.core.entity.player.InteractionHand; import net.momirealms.craftengine.core.entity.player.Player; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java deleted file mode 100644 index eaa50da56..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateHolder.java +++ /dev/null @@ -1,131 +0,0 @@ -package net.momirealms.craftengine.core.block; - -import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; -import net.momirealms.craftengine.core.block.properties.Property; -import net.momirealms.craftengine.core.registry.Holder; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.stream.Collectors; - -public class BlockStateHolder { - protected final Holder.Reference owner; - private final Reference2ObjectArrayMap, Comparable> propertyMap; - private Map, ImmutableBlockState[]> withMap; - - public BlockStateHolder(Holder.Reference owner, Reference2ObjectArrayMap, Comparable> propertyMap) { - this.owner = owner; - this.propertyMap = new Reference2ObjectArrayMap<>(propertyMap); - } - - public Holder owner() { - return this.owner; - } - - public > ImmutableBlockState cycle(Property property) { - T currentValue = get(property); - List values = property.possibleValues(); - return with(property, getNextValue(values, currentValue)); - } - - protected static T getNextValue(List values, T currentValue) { - int index = values.indexOf(currentValue); - if (index == -1) { - throw new IllegalArgumentException("Current value not found in possible values"); - } - return values.get((index + 1) % values.size()); - } - - @Override - public String toString() { - if (this.propertyMap.isEmpty()) { - return this.owner.key().location().toString(); - } - return this.owner.key().location() + "[" + getPropertiesAsString() + "]"; - } - - public String getPropertiesAsString() { - return this.propertyMap.entrySet().stream() - .map(entry -> { - Property property = entry.getKey(); - return property.name() + "=" + Property.formatValue(property, entry.getValue()); - }) - .collect(Collectors.joining(",")); - } - - public Collection> getProperties() { - return Collections.unmodifiableSet(this.propertyMap.keySet()); - } - - public > boolean contains(Property property) { - return this.propertyMap.containsKey(property); - } - - public > T get(Property property) { - T value = getNullable(property); - if (value == null) { - throw new IllegalArgumentException("Property " + property + " not found in " + this.owner.value().id()); - } - return value; - } - - public > T get(Property property, T fallback) { - return Objects.requireNonNullElse(getNullable(property), fallback); - } - - @Nullable - public > T getNullable(Property property) { - Comparable value = this.propertyMap.get(property); - return value != null ? property.valueClass().cast(value) : null; - } - - public , V extends T> ImmutableBlockState with(Property property, V value) { - if (!this.propertyMap.containsKey(property)) { - throw new IllegalArgumentException("Property " + property + " not found in " + this.owner.value().id()); - } - return withInternal(property, value); - } - - private , V extends T> ImmutableBlockState withInternal(Property property, V newValue) { - if (newValue.equals(this.propertyMap.get(property))) { - return (ImmutableBlockState) this; - } - - int index = property.indexOf(newValue); - if (index == -1) { - throw new IllegalArgumentException("Invalid value " + newValue + " for property " + property); - } - - return this.withMap.get(property)[index]; - } - - public void createWithMap(Map, Comparable>, ImmutableBlockState> states) { - if (this.withMap != null) { - throw new IllegalStateException("WithMap already initialized"); - } - - Reference2ObjectArrayMap, ImmutableBlockState[]> map = new Reference2ObjectArrayMap<>(this.propertyMap.size()); - - for (Property property : this.propertyMap.keySet()) { - ImmutableBlockState[] statesArray = property.possibleValues().stream() - .map(value -> { - Map, Comparable> testMap = new Reference2ObjectArrayMap<>(this.propertyMap); - testMap.put(property, value); - ImmutableBlockState state = states.get(testMap); - if (state == null) { - throw new IllegalStateException("Missing state for " + testMap); - } - return state; - }) - .toArray(ImmutableBlockState[]::new); - - map.put(property, statesArray); - } - - this.withMap = Map.copyOf(map); - } - - public Map, Comparable> propertyEntries() { - return Collections.unmodifiableMap(this.propertyMap); - } -} \ No newline at end of file diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index 8a68b9527..e2752a6c4 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -7,6 +7,7 @@ import net.momirealms.craftengine.core.block.entity.BlockEntityType; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; import net.momirealms.craftengine.core.block.entity.tick.BlockEntityTicker; +import net.momirealms.craftengine.core.block.properties.EnumProperty; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; @@ -22,9 +23,14 @@ import net.momirealms.sparrow.nbt.Tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; + +public final class ImmutableBlockState { + private final Holder.Reference owner; + private final Reference2ObjectArrayMap, Comparable> propertyMap; + private Map, ImmutableBlockState[]> withMap; -public final class ImmutableBlockState extends BlockStateHolder { private CompoundTag tag; private BlockStateWrapper customBlockState; private BlockStateWrapper vanillaBlockState; @@ -38,7 +44,8 @@ public final class ImmutableBlockState extends BlockStateHolder { Holder.Reference owner, Reference2ObjectArrayMap, Comparable> propertyMap ) { - super(owner, propertyMap); + this.owner = owner; + this.propertyMap = new Reference2ObjectArrayMap<>(propertyMap); } public BlockBehavior behavior() { @@ -101,24 +108,6 @@ public final class ImmutableBlockState extends BlockStateHolder { this.vanillaBlockState = vanillaBlockState; } - public CompoundTag propertiesNbt() { - CompoundTag properties = new CompoundTag(); - for (Property property : getProperties()) { - Comparable value = get(property); - if (value != null) { - properties.put(property.name(), pack(property, value)); - continue; - } - properties.put(property.name(), pack(property, property.defaultValue())); - } - return properties; - } - - @SuppressWarnings("unchecked") - public static > Tag pack(Property property, Object value) { - return property.pack((T) value); - } - public CompoundTag getNbtToSave() { if (this.tag == null) { this.tag = toNbtToSave(propertiesNbt()); @@ -137,11 +126,6 @@ public final class ImmutableBlockState extends BlockStateHolder { this.tag = tag; } - @SuppressWarnings("unchecked") - public static > ImmutableBlockState with(ImmutableBlockState state, Property property, Object value) { - return state.with(property, (T) value); - } - @SuppressWarnings("unchecked") public List> getDrops(@NotNull ContextHolder.Builder builder, @NotNull World world, @Nullable Player player) { CustomBlock block = this.owner.value(); @@ -164,4 +148,146 @@ public final class ImmutableBlockState extends BlockStateHolder { if (blockBehavior == null) return null; return (BlockEntityTicker) blockBehavior.createAsyncBlockEntityTicker(world, this, type); } + + public Holder owner() { + return this.owner; + } + + public > ImmutableBlockState cycle(Property property) { + T currentValue = get(property); + List values = property.possibleValues(); + return with(property, getNextValue(values, currentValue)); + } + + private static T getNextValue(List values, T currentValue) { + int index = values.indexOf(currentValue); + if (index == -1) { + throw new IllegalArgumentException("Current value not found in possible values"); + } + return values.get((index + 1) % values.size()); + } + + @Override + public String toString() { + if (this.propertyMap.isEmpty()) { + return this.owner.key().location().toString(); + } + return this.owner.key().location() + "[" + getPropertiesAsString() + "]"; + } + + public String getPropertiesAsString() { + return this.propertyMap.entrySet().stream() + .map(entry -> { + Property property = entry.getKey(); + return property.name() + "=" + Property.formatValue(property, entry.getValue()); + }) + .collect(Collectors.joining(",")); + } + + public Collection> getProperties() { + return Collections.unmodifiableSet(this.propertyMap.keySet()); + } + + public > boolean contains(Property property) { + return this.propertyMap.containsKey(property); + } + + public > T get(Property property) { + T value = getNullable(property); + if (value == null) { + throw new IllegalArgumentException("Property " + property + " not found in " + this.owner.value().id()); + } + return value; + } + + public > T get(Property property, T fallback) { + return Objects.requireNonNullElse(getNullable(property), fallback); + } + + @Nullable + public > T getNullable(Property property) { + Comparable value = this.propertyMap.get(property); + return value != null ? property.valueClass().cast(value) : null; + } + + public CompoundTag propertiesNbt() { + CompoundTag properties = new CompoundTag(); + for (Map.Entry, Comparable> entry : this.propertyMap.entrySet()) { + Property property = entry.getKey(); + properties.put(property.name(), pack(property, entry.getValue())); + } + return properties; + } + + @SuppressWarnings("unchecked") + private static > Tag pack(Property property, Object value) { + return property.pack((T) value); + } + + @SuppressWarnings("unchecked") + public static > ImmutableBlockState with(ImmutableBlockState state, Property property, Object value) { + return state.with(property, (T) value); + } + + public ImmutableBlockState with(CompoundTag propertiesNBT) { + CustomBlock owner = this.owner.value(); + ImmutableBlockState finalState = this; + for (Map.Entry entry : propertiesNBT.entrySet()) { + Property property = owner.getProperty(entry.getKey()); + if (property != null) { + finalState = with(finalState, property, property.unpack(entry.getValue())); + } + } + return finalState; + } + + public , V extends T> ImmutableBlockState with(Property property, V value) { + if (!this.propertyMap.containsKey(property)) { + throw new IllegalArgumentException("Property " + property + " not found in " + this.owner.value().id()); + } + return withInternal(property, value); + } + + private , V extends T> ImmutableBlockState withInternal(Property property, V newValue) { + if (newValue.equals(this.propertyMap.get(property))) { + return this; + } + + int index = property.indexOf(newValue); + if (index == -1) { + throw new IllegalArgumentException("Invalid value " + newValue + " for property " + property); + } + + return this.withMap.get(property)[index]; + } + + public void createWithMap(Map, Comparable>, ImmutableBlockState> states) { + if (this.withMap != null) { + throw new IllegalStateException("WithMap already initialized"); + } + + Reference2ObjectArrayMap, ImmutableBlockState[]> map = new Reference2ObjectArrayMap<>(this.propertyMap.size()); + + for (Property property : this.propertyMap.keySet()) { + ImmutableBlockState[] statesArray = property.possibleValues().stream() + .map(value -> { + Map, Comparable> testMap = new Reference2ObjectArrayMap<>(this.propertyMap); + testMap.put(property, value); + ImmutableBlockState state = states.get(testMap); + if (state == null) { + throw new IllegalStateException("Missing state for " + testMap); + } + return state; + }) + .toArray(ImmutableBlockState[]::new); + + map.put(property, statesArray); + } + + this.withMap = Map.copyOf(map); + } + + public Map, Comparable> propertyEntries() { + return Collections.unmodifiableMap(this.propertyMap); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/BooleanProperty.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/BooleanProperty.java index 2e9798331..526f51d5f 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/BooleanProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/BooleanProperty.java @@ -54,6 +54,16 @@ public class BooleanProperty extends Property { return bool.toString(); } + @Override + public Boolean valueByName(String name) { + if (name.equals("true")) { + return true; + } else if (name.equals("false")) { + return false; + } + return null; + } + @Override public int indexOf(Boolean bool) { return bool ? 0 : 1; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/EnumProperty.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/EnumProperty.java index d26941108..3ff181c94 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/EnumProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/EnumProperty.java @@ -86,6 +86,11 @@ public class EnumProperty> extends Property { return value.name().toLowerCase(Locale.ENGLISH); } + @Override + public T valueByName(String name) { + return this.names.get(name.toLowerCase(Locale.ENGLISH)); + } + @Override public int indexOf(T value) { return this.ordinalToIndex[value.ordinal()]; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/IntegerProperty.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/IntegerProperty.java index 7b77e0bd0..95b989567 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/IntegerProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/IntegerProperty.java @@ -6,6 +6,7 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.sparrow.nbt.IntTag; import net.momirealms.sparrow.nbt.NumericTag; import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; @@ -76,6 +77,16 @@ public class IntegerProperty extends Property { return integer.toString(); } + @Override + public Integer valueByName(String name) { + try { + int i = Integer.parseInt(name); + return i >= this.min && i <= this.max ? i : null; + } catch (NumberFormatException var3) { + return null; + } + } + @Override public int indexOf(Integer integer) { return integer <= this.max ? integer - this.min : -1; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java index fc3370fac..cacd02165 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java @@ -112,6 +112,9 @@ public abstract class Property> { return indexOf(unpack(tag)); } + @Nullable + public abstract T valueByName(String name); + public abstract int indexOf(T value); public abstract T unpack(Tag tag); diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/StringProperty.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/StringProperty.java index c6ef572e3..3d68ce99a 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/StringProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/StringProperty.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.sparrow.nbt.StringTag; import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Locale; @@ -36,7 +37,7 @@ public class StringProperty extends Property { @Override public Optional optional(String valueName) { - return Optional.ofNullable(this.names.get(valueName.toLowerCase(Locale.ENGLISH))); + return Optional.ofNullable(this.names.get(valueName)); } @Override @@ -59,7 +60,7 @@ public class StringProperty extends Property { @Override public final int idFor(String value) { - int index = indexOf(value.toLowerCase(Locale.ENGLISH)); + int index = indexOf(value); if (index == -1) { throw new IllegalArgumentException("Invalid value: " + value); } @@ -68,12 +69,17 @@ public class StringProperty extends Property { @Override public String valueName(String value) { - return value.toLowerCase(Locale.ENGLISH); + return value; + } + + @Override + public String valueByName(String name) { + return this.names.get(name); } @Override public int indexOf(String value) { - return values.indexOf(value.toLowerCase(Locale.ENGLISH)); + return this.values.indexOf(value); } @Override @@ -92,13 +98,12 @@ public class StringProperty extends Property { public Property create(String name, Map arguments) { List values = MiscUtils.getAsStringList(arguments.get("values")) .stream() - .map(it -> it.toLowerCase(Locale.ENGLISH)) .toList(); - String defaultValueName = arguments.getOrDefault("default", "").toString().toLowerCase(Locale.ENGLISH); + String defaultValueName = arguments.getOrDefault("default", "").toString(); String defaultValue = values.stream() - .filter(e -> e.toLowerCase(Locale.ENGLISH).equals(defaultValueName)) + .filter(e -> e.equals(defaultValueName)) .findFirst() - .orElseGet(() -> values.get(0)); + .orElseGet(values::getFirst); return StringProperty.create(name, values, defaultValue); } } From b74cb78ef4ef280f8cc9959f83858c5d76a0d7f2 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 16:42:25 +0800 Subject: [PATCH 115/125] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=BD=AC=E5=8C=96?= =?UTF-8?q?=E7=B1=BB=E8=A1=8C=E4=B8=BA=E7=9B=AE=E6=A0=87=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../block/BukkitCustomBlockStateWrapper.java | 16 ++++++ .../block/BukkitVanillaBlockStateWrapper.java | 9 +++ .../behavior/ChangeOverTimeBlockBehavior.java | 55 ++++++++++++++----- .../behavior/StrippableBlockBehavior.java | 27 ++++++--- .../bukkit/item/behavior/AxeItemBehavior.java | 12 ++-- .../core/block/BlockStateWrapper.java | 20 +++++++ .../core/block/ImmutableBlockState.java | 1 - .../core/block/StatePropertyAccessor.java | 5 ++ .../block/properties/IntegerProperty.java | 1 - .../core/block/properties/Property.java | 3 +- .../core/block/properties/StringProperty.java | 2 - gradle.properties | 2 +- 12 files changed, 119 insertions(+), 34 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java index f336c1cbb..cf4cda67b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitCustomBlockStateWrapper.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.block; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.AbstractBlockStateWrapper; +import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.ImmutableBlockState; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.util.Key; @@ -30,6 +31,21 @@ public class BukkitCustomBlockStateWrapper extends AbstractBlockStateWrapper { }).orElse(null); } + @Override + public BlockStateWrapper withProperty(String propertyName, String propertyValue) { + Optional immutableBlockState = getImmutableBlockState(); + if (immutableBlockState.isPresent()) { + Property property = immutableBlockState.get().owner().value().getProperty(propertyName); + if (property != null) { + Comparable value = property.valueByName(propertyValue); + if (value != null) { + return ImmutableBlockState.with(immutableBlockState.get(), property, value).customBlockState(); + } + } + } + return this; + } + @Override public boolean hasProperty(String propertyName) { return getImmutableBlockState().map(state -> state.owner().value().getProperty(propertyName) != null).orElse(false); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java index 9a13a5d13..61c5d7172 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitVanillaBlockStateWrapper.java @@ -3,6 +3,8 @@ package net.momirealms.craftengine.bukkit.block; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.AbstractBlockStateWrapper; +import net.momirealms.craftengine.core.block.BlockRegistryMirror; +import net.momirealms.craftengine.core.block.BlockStateWrapper; import net.momirealms.craftengine.core.block.StatePropertyAccessor; import net.momirealms.craftengine.core.util.Key; @@ -33,4 +35,11 @@ public class BukkitVanillaBlockStateWrapper extends AbstractBlockStateWrapper { public String getAsString() { return BlockStateUtils.fromBlockData(super.blockState).getAsString(); } + + @Override + public BlockStateWrapper withProperty(String propertyName, String propertyValue) { + Object newState = this.accessor.withProperty(propertyName, propertyValue); + if (newState == super.blockState) return this; + return BlockRegistryMirror.byId(BlockStateUtils.blockStateToId(newState)); + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java index b6a40cf8f..14cfb8f28 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java @@ -2,12 +2,14 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; +import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.core.block.*; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; -import net.momirealms.craftengine.core.util.Key; -import net.momirealms.craftengine.core.util.RandomUtils; -import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.util.*; +import net.momirealms.sparrow.nbt.CompoundTag; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.Callable; @@ -15,23 +17,47 @@ import java.util.concurrent.Callable; public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final float changeSpeed; - private final Key nextBlock; + private final String nextBlock; + private final LazyReference lazyState; + private final List excludedProperties; - public ChangeOverTimeBlockBehavior(CustomBlock customBlock, float changeSpeed, Key nextBlock) { + public ChangeOverTimeBlockBehavior(CustomBlock customBlock, float changeSpeed, String nextBlock, List excludedProperties) { super(customBlock); this.changeSpeed = changeSpeed; this.nextBlock = nextBlock; + this.excludedProperties = excludedProperties; + this.lazyState = LazyReference.lazyReference(() -> CraftEngine.instance().blockManager().createBlockState(this.nextBlock)); + } + + public String nextBlock() { + return nextBlock; + } + + public BlockStateWrapper nextState() { + return this.lazyState.get(); + } + + public CompoundTag filter(CompoundTag properties) { + for (String property : this.excludedProperties) { + properties.remove(property); + } + return properties; } @Override - public void randomTick(Object thisBlock, Object[] args, Callable superMethod) throws ReflectiveOperationException { + public void randomTick(Object thisBlock, Object[] args, Callable superMethod) { if (RandomUtils.generateRandomFloat(0F, 1F) >= this.changeSpeed) return; - Optional nextState = BukkitBlockManager.instance().blockById(this.nextBlock) - .map(CustomBlock::defaultState) - .map(ImmutableBlockState::customBlockState) - .map(BlockStateWrapper::literalObject); - if (nextState.isEmpty()) return; - CraftBukkitReflections.method$CraftEventFactory$handleBlockFormEvent.invoke(null, args[1], args[2], nextState.get(), UpdateOption.UPDATE_ALL.flags()); + Object blockState = args[0]; + BlockStateUtils.getOptionalCustomBlockState(blockState).ifPresent(state -> { + BlockStateWrapper nextState = this.nextState(); + if (nextState == null) return; + nextState = nextState.withProperties(filter(state.propertiesNbt())); + try { + CraftBukkitReflections.method$CraftEventFactory$handleBlockFormEvent.invoke(null, args[1], args[2], nextState.literalObject(), UpdateOption.UPDATE_ALL.flags()); + } catch (ReflectiveOperationException e) { + CraftEngine.instance().logger().warn("Failed to call block form event", e); + } + }); } public static class Factory implements BlockBehaviorFactory { @@ -39,8 +65,9 @@ public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior { @Override public BlockBehavior create(CustomBlock block, Map arguments) { float changeSpeed = ResourceConfigUtils.getAsFloat(arguments.getOrDefault("change-speed", 0.05688889F), "change-speed"); - Key nextBlock = Key.of(ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.getOrDefault("next-block", "minecraft:air"), "warning.config.block.behavior.change_over_time.missing_next_block")); - return new ChangeOverTimeBlockBehavior(block, changeSpeed, nextBlock); + String nextBlock = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.getOrDefault("next-block", "minecraft:air"), "warning.config.block.behavior.change_over_time.missing_next_block"); + List excludedProperties = MiscUtils.getAsStringList(arguments.get("excluded-properties")); + return new ChangeOverTimeBlockBehavior(block, changeSpeed, nextBlock, excludedProperties); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java index a1b243ee9..bbe9837ae 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/StrippableBlockBehavior.java @@ -1,40 +1,53 @@ package net.momirealms.craftengine.bukkit.block.behavior; import net.momirealms.craftengine.core.block.BlockBehavior; +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.BlockBehaviorFactory; -import net.momirealms.craftengine.core.block.parser.BlockStateParser; +import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.LazyReference; +import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import net.momirealms.sparrow.nbt.CompoundTag; +import java.util.List; import java.util.Map; public class StrippableBlockBehavior extends BukkitBlockBehavior { public static final Factory FACTORY = new Factory(); private final String stripped; - private final LazyReference lazyState; + private final LazyReference lazyState; + private final List excludedProperties; - public StrippableBlockBehavior(CustomBlock block, String stripped) { + public StrippableBlockBehavior(CustomBlock block, String stripped, List excludedProperties) { super(block); this.stripped = stripped; - this.lazyState = LazyReference.lazyReference(() -> BlockStateParser.deserialize(this.stripped)); + this.lazyState = LazyReference.lazyReference(() -> CraftEngine.instance().blockManager().createBlockState(this.stripped)); + this.excludedProperties = excludedProperties; } public String stripped() { return this.stripped; } - public ImmutableBlockState strippedState() { + public BlockStateWrapper strippedState() { return this.lazyState.get(); } + public CompoundTag filter(CompoundTag properties) { + for (String property : this.excludedProperties) { + properties.remove(property); + } + return properties; + } + public static class Factory implements BlockBehaviorFactory { @Override public BlockBehavior create(CustomBlock block, Map arguments) { String stripped = ResourceConfigUtils.requireNonEmptyStringOrThrow(arguments.get("stripped"), "warning.config.block.behavior.strippable.missing_stripped"); - return new StrippableBlockBehavior(block, stripped); + List excludedProperties = MiscUtils.getAsStringList(arguments.get("excluded-properties")); + return new StrippableBlockBehavior(block, stripped, excludedProperties); } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java index 882ba4be5..6d23f2ec7 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/behavior/AxeItemBehavior.java @@ -70,21 +70,19 @@ public class AxeItemBehavior extends ItemBehavior { return InteractionResult.PASS; } - ImmutableBlockState newState = behaviorOptional.get().strippedState(); + BlockStateWrapper newState = behaviorOptional.get().strippedState(); if (newState == null) { CraftEngine.instance().logger().warn("stripped block " + behaviorOptional.get().stripped() + " does not exist"); return InteractionResult.FAIL; } - BlockStateWrapper - - newState = newState.with(customState.propertiesNbt()); + newState = newState.withProperties(behaviorOptional.get().filter(customState.propertiesNbt())); BukkitExistingBlock clicked = (BukkitExistingBlock) context.getLevel().getBlockAt(context.getClickedPos()); org.bukkit.entity.Player bukkitPlayer = null; if (player != null) { bukkitPlayer = ((org.bukkit.entity.Player) player.platformPlayer()); // Call bukkit event - EntityChangeBlockEvent event = new EntityChangeBlockEvent(bukkitPlayer, clicked.block(), BlockStateUtils.fromBlockData(newState.customBlockState().literalObject())); + EntityChangeBlockEvent event = new EntityChangeBlockEvent(bukkitPlayer, clicked.block(), BlockStateUtils.fromBlockData(newState.literalObject())); if (EventUtils.fireAndCheckCancel(event)) { return InteractionResult.FAIL; } @@ -95,7 +93,7 @@ public class AxeItemBehavior extends ItemBehavior { 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().literalObject(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags()); + FastNMS.INSTANCE.method$LevelWriter$setBlock(context.getLevel().serverWorld(), LocationUtils.toBlockPos(pos), newState.literalObject(), UpdateOption.UPDATE_ALL_IMMEDIATE.flags()); clicked.block().getWorld().sendGameEvent(bukkitPlayer, GameEvent.BLOCK_CHANGE, new Vector(pos.x(), pos.y(), pos.z())); Material material = MaterialUtils.getMaterial(item.vanillaId()); if (bukkitPlayer != null) { @@ -123,7 +121,7 @@ public class AxeItemBehavior extends ItemBehavior { itemStack.damage(1, bukkitPlayer); } } - return InteractionResult.SUCCESS; + return InteractionResult.SUCCESS_AND_CANCEL; } public static class Factory implements ItemBehaviorFactory { diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java index 5ef5223b1..d8c97482b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockStateWrapper.java @@ -1,8 +1,11 @@ package net.momirealms.craftengine.core.block; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.*; import org.jetbrains.annotations.NotNull; +import java.util.Map; + public interface BlockStateWrapper extends Comparable { Object literalObject(); @@ -15,10 +18,27 @@ public interface BlockStateWrapper extends Comparable { boolean hasProperty(String propertyName); + BlockStateWrapper withProperty(String propertyName, String propertyValue); + String getAsString(); @Override default int compareTo(@NotNull BlockStateWrapper o) { return Integer.compare(registryId(), o.registryId()); } + + default BlockStateWrapper withProperties(CompoundTag properties) { + BlockStateWrapper result = this; + for (Map.Entry entry : properties.entrySet()) { + Tag value = entry.getValue(); + if (value instanceof StringTag stringTag) { + result = result.withProperty(entry.getKey(), stringTag.getAsString()); + } else if (value instanceof IntTag intTag) { + result = result.withProperty(entry.getKey(), String.valueOf(intTag.getAsInt())); + } else if (value instanceof ByteTag byteTag) { + result = result.withProperty(entry.getKey(), String.valueOf(byteTag.booleanValue())); + } + } + return result; + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java index e2752a6c4..c46a69faf 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/ImmutableBlockState.java @@ -7,7 +7,6 @@ import net.momirealms.craftengine.core.block.entity.BlockEntityType; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElement; import net.momirealms.craftengine.core.block.entity.render.element.BlockEntityElementConfig; import net.momirealms.craftengine.core.block.entity.tick.BlockEntityTicker; -import net.momirealms.craftengine.core.block.properties.EnumProperty; import net.momirealms.craftengine.core.block.properties.Property; import net.momirealms.craftengine.core.entity.player.Player; import net.momirealms.craftengine.core.item.Item; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java b/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java index 3e1a46e3f..1277e0b1e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/StatePropertyAccessor.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.core.block; +import org.jetbrains.annotations.NotNull; + import java.util.Collection; public interface StatePropertyAccessor { @@ -11,4 +13,7 @@ public interface StatePropertyAccessor { boolean hasProperty(String property); T getPropertyValue(String property); + + @NotNull + Object withProperty(String propertyName, String value); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/IntegerProperty.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/IntegerProperty.java index 95b989567..00bf88224 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/IntegerProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/IntegerProperty.java @@ -6,7 +6,6 @@ import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.sparrow.nbt.IntTag; import net.momirealms.sparrow.nbt.NumericTag; import net.momirealms.sparrow.nbt.Tag; -import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java index cacd02165..f89787fa1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/Property.java @@ -5,6 +5,7 @@ import net.momirealms.craftengine.core.item.context.BlockPlaceContext; import net.momirealms.craftengine.core.util.Direction; import net.momirealms.craftengine.core.util.HorizontalDirection; import net.momirealms.sparrow.nbt.Tag; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -155,7 +156,7 @@ public abstract class Property> { } @Override - public String toString() { + public @NotNull String toString() { return this.property.name + "=" + this.property.valueName(this.value); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/properties/StringProperty.java b/core/src/main/java/net/momirealms/craftengine/core/block/properties/StringProperty.java index 3d68ce99a..f9a556df3 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/properties/StringProperty.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/properties/StringProperty.java @@ -4,10 +4,8 @@ import com.google.common.collect.ImmutableMap; import net.momirealms.craftengine.core.util.MiscUtils; import net.momirealms.sparrow.nbt.StringTag; import net.momirealms.sparrow.nbt.Tag; -import org.jetbrains.annotations.Nullable; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Optional; diff --git a/gradle.properties b/gradle.properties index 153a6411f..006b5a0c5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -50,7 +50,7 @@ byte_buddy_version=1.17.5 ahocorasick_version=0.6.3 snake_yaml_version=2.5 anti_grief_version=1.0.2 -nms_helper_version=1.0.103 +nms_helper_version=1.0.104 evalex_version=3.5.0 reactive_streams_version=1.0.4 amazon_awssdk_version=2.34.5 From 8b40a2dad49ddba7a97fe94d25c3e8b520e9f548 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 16:48:29 +0800 Subject: [PATCH 116/125] Update ChangeOverTimeBlockBehavior.java --- .../block/behavior/ChangeOverTimeBlockBehavior.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java index 14cfb8f28..49ad41749 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/ChangeOverTimeBlockBehavior.java @@ -1,17 +1,21 @@ package net.momirealms.craftengine.bukkit.block.behavior; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; -import net.momirealms.craftengine.core.block.*; +import net.momirealms.craftengine.core.block.BlockBehavior; +import net.momirealms.craftengine.core.block.BlockStateWrapper; +import net.momirealms.craftengine.core.block.CustomBlock; +import net.momirealms.craftengine.core.block.UpdateOption; import net.momirealms.craftengine.core.block.behavior.BlockBehaviorFactory; import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.*; +import net.momirealms.craftengine.core.util.LazyReference; +import net.momirealms.craftengine.core.util.MiscUtils; +import net.momirealms.craftengine.core.util.RandomUtils; +import net.momirealms.craftengine.core.util.ResourceConfigUtils; import net.momirealms.sparrow.nbt.CompoundTag; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.concurrent.Callable; public class ChangeOverTimeBlockBehavior extends BukkitBlockBehavior { From eec7cf4903ec2983e0d1035a86cc4e62f30d64a8 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 18:58:38 +0800 Subject: [PATCH 117/125] Update ResolutionMergePackMcMeta.java --- .../resolution/ResolutionMergePackMcMeta.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java index be609eeb1..0c4a78759 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/conflict/resolution/ResolutionMergePackMcMeta.java @@ -186,8 +186,21 @@ public class ResolutionMergePackMcMeta implements Resolution { } if (supported.isJsonPrimitive()) { - int value = supported.getAsInt(); - return new MinMax(value, value); + if (supported.getAsJsonPrimitive().isNumber()) { + int value = supported.getAsInt(); + return new MinMax(value, value); + } else if (supported.getAsJsonPrimitive().isString()) { + String value = supported.getAsString(); + if (value.contains(",")) { + String[] parts = value.replace("[", "").replace("]", "").split(","); + int min = Integer.parseInt(parts[0]); + int max = Integer.parseInt(parts[1]); + return new MinMax(min, max); + } else { + int min = Integer.parseInt(value); + return new MinMax(min, min); + } + } } if (supported.isJsonArray()) { From e24671d058e688bd926082564ec0955db0b59680 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 18:59:00 +0800 Subject: [PATCH 118/125] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 006b5a0c5..76a17095e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.10 +project_version=0.0.63.11 config_version=47 lang_version=33 project_group=net.momirealms From 4ababdf11387a5e5f88ba0a8060b7e076379aad4 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 19:12:52 +0800 Subject: [PATCH 119/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B9=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84?= =?UTF-8?q?=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/plugin/command/feature/DebugCleanCacheCommand.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java index bf41e6f10..126e06e3e 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/command/feature/DebugCleanCacheCommand.java @@ -175,6 +175,9 @@ public class DebugCleanCacheCommand extends BukkitCommandFeature public Map getAllCachedCustomModelData() { Path cacheDir = CraftEngine.instance().dataFolderPath().resolve("cache").resolve("custom-model-data"); + if (!Files.exists(cacheDir)) { + return Map.of(); + } Map idAllocators = new HashMap<>(); try (Stream files = Files.list(cacheDir)) { From 89df1b4c256b9ef1734914a8347a2ffdb6ecd7ba Mon Sep 17 00:00:00 2001 From: jhqwqmc Date: Mon, 6 Oct 2025 20:21:20 +0800 Subject: [PATCH 120/125] =?UTF-8?q?=E6=B7=BB=E5=8A=A0qs=E5=85=BC=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/compatibility/build.gradle.kts | 3 + .../BukkitCompatibilityManager.java | 5 ++ .../QuickShopItemExpressionHandler.java | 56 +++++++++++++++++++ bukkit/paper-loader/build.gradle.kts | 1 + 4 files changed, 65 insertions(+) create mode 100644 bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java diff --git a/bukkit/compatibility/build.gradle.kts b/bukkit/compatibility/build.gradle.kts index 520da0749..df485034a 100644 --- a/bukkit/compatibility/build.gradle.kts +++ b/bukkit/compatibility/build.gradle.kts @@ -16,6 +16,7 @@ repositories { maven("https://repo.auxilor.io/repository/maven-public/") // eco maven("https://repo.hiusers.com/releases") // zaphkiel maven("https://jitpack.io") // sxitem slimefun + maven("https://repo.codemc.io/repository/maven-public/") // quickshop } dependencies { @@ -79,6 +80,8 @@ dependencies { compileOnly("com.github.Saukiya:SX-Item:4.4.6") // Slimefun compileOnly("io.github.Slimefun:Slimefun4:RC-32") + // QuickShop + compileOnly("com.ghostchu:quickshop-api:6.2.0.10") } java { diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/BukkitCompatibilityManager.java index f35396548..79df69a97 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 @@ -12,6 +12,7 @@ import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicItemDrop import net.momirealms.craftengine.bukkit.compatibility.mythicmobs.MythicSkillHelper; import net.momirealms.craftengine.bukkit.compatibility.papi.PlaceholderAPIUtils; import net.momirealms.craftengine.bukkit.compatibility.permission.LuckPermsEventListeners; +import net.momirealms.craftengine.bukkit.compatibility.quickshop.QuickShopItemExpressionHandler; import net.momirealms.craftengine.bukkit.compatibility.region.WorldGuardRegionCondition; import net.momirealms.craftengine.bukkit.compatibility.skript.SkriptHook; import net.momirealms.craftengine.bukkit.compatibility.slimeworld.SlimeFormatStorageAdaptor; @@ -141,6 +142,10 @@ public class BukkitCompatibilityManager implements CompatibilityManager { ModelEngineUtils.registerConstantBlockEntityRender(); logHook("ModelEngine"); } + if (this.isPluginEnabled("QuickShop-Hikari")) { + new QuickShopItemExpressionHandler(this.plugin); + logHook("QuickShop-Hikari"); + } } @Override diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java new file mode 100644 index 000000000..36919172f --- /dev/null +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java @@ -0,0 +1,56 @@ +package net.momirealms.craftengine.bukkit.compatibility.quickshop; + +import com.ghostchu.quickshop.api.QuickShopAPI; +import com.ghostchu.quickshop.api.event.QSConfigurationReloadEvent; +import com.ghostchu.quickshop.api.registry.BuiltInRegistry; +import com.ghostchu.quickshop.api.registry.Registry; +import com.ghostchu.quickshop.api.registry.builtin.itemexpression.ItemExpressionHandler; +import com.ghostchu.quickshop.api.registry.builtin.itemexpression.ItemExpressionRegistry; +import net.momirealms.craftengine.bukkit.api.CraftEngineItems; +import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; +import net.momirealms.craftengine.core.util.Key; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +public class QuickShopItemExpressionHandler implements ItemExpressionHandler, Listener { + private final BukkitCraftEngine plugin; + + public QuickShopItemExpressionHandler(BukkitCraftEngine plugin) { + this.plugin = plugin; + Bukkit.getPluginManager().registerEvents(this, plugin.javaPlugin()); + init(); + } + + public void init() { + Registry registry = QuickShopAPI.getInstance().getRegistry().getRegistry(BuiltInRegistry.ITEM_EXPRESSION); + if (!(registry instanceof ItemExpressionRegistry itemExpressionRegistry)) return; + if (!itemExpressionRegistry.registerHandlerSafely(this)) return; + this.plugin.logger().info("[Compatibility] Successfully registered CraftEngine ItemExpressionHandler to QuickShop-Hikari"); + } + + @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) + public void onQuickShopReload(final QSConfigurationReloadEvent event) { + init(); + } + + @Override + public @NotNull Plugin getPlugin() { + return this.plugin.javaPlugin(); + } + + @Override + public String getPrefix() { + return "craftengine"; + } + + @Override + public boolean match(ItemStack itemStack, String id) { + Key customId = CraftEngineItems.getCustomItemId(itemStack); + return customId != null && id.equals(customId.asString()); + } +} diff --git a/bukkit/paper-loader/build.gradle.kts b/bukkit/paper-loader/build.gradle.kts index 293cfb09f..9b04d929d 100644 --- a/bukkit/paper-loader/build.gradle.kts +++ b/bukkit/paper-loader/build.gradle.kts @@ -75,6 +75,7 @@ paper { } register("LuckPerms") { required = false } register("ViaVersion") { required = false } + register("QuickShop-Hikari") { required = false } // external models register("ModelEngine") { required = false } From 010461c03e5fdf0463fd72900d619b69dd4f38aa Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 20:46:45 +0800 Subject: [PATCH 121/125] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../quickshop/QuickShopItemExpressionHandler.java | 11 ++++++----- gradle.properties | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java index 36919172f..2f429bcdb 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java @@ -23,19 +23,20 @@ public class QuickShopItemExpressionHandler implements ItemExpressionHandler, Li public QuickShopItemExpressionHandler(BukkitCraftEngine plugin) { this.plugin = plugin; Bukkit.getPluginManager().registerEvents(this, plugin.javaPlugin()); - init(); + register(); } - public void init() { + public void register() { Registry registry = QuickShopAPI.getInstance().getRegistry().getRegistry(BuiltInRegistry.ITEM_EXPRESSION); if (!(registry instanceof ItemExpressionRegistry itemExpressionRegistry)) return; - if (!itemExpressionRegistry.registerHandlerSafely(this)) return; - this.plugin.logger().info("[Compatibility] Successfully registered CraftEngine ItemExpressionHandler to QuickShop-Hikari"); + if (!itemExpressionRegistry.registerHandlerSafely(this)) { + + } } @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) public void onQuickShopReload(final QSConfigurationReloadEvent event) { - init(); + register(); } @Override diff --git a/gradle.properties b/gradle.properties index 76a17095e..2b0c372b7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -39,7 +39,7 @@ zstd_version=1.5.7-4 commons_io_version=2.20.0 commons_imaging_version=1.0.0-alpha6 commons_lang3_version=3.19.0 -sparrow_nbt_version=0.9.8 +sparrow_nbt_version=0.9.9 sparrow_util_version=0.51 fastutil_version=8.5.16 netty_version=4.1.127.Final From 001366336c7d66a8327e273560342f31fb9032da Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 20:47:01 +0800 Subject: [PATCH 122/125] Update QuickShopItemExpressionHandler.java --- .../quickshop/QuickShopItemExpressionHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java index 2f429bcdb..148dafeaa 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java @@ -29,9 +29,7 @@ public class QuickShopItemExpressionHandler implements ItemExpressionHandler, Li public void register() { Registry registry = QuickShopAPI.getInstance().getRegistry().getRegistry(BuiltInRegistry.ITEM_EXPRESSION); if (!(registry instanceof ItemExpressionRegistry itemExpressionRegistry)) return; - if (!itemExpressionRegistry.registerHandlerSafely(this)) { - - } + itemExpressionRegistry.registerHandlerSafely(this); } @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) From 67f8e0d5e7c8fd80e17b3a327ac6503424cf6a70 Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 22:32:52 +0800 Subject: [PATCH 123/125] =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E7=9B=91=E5=90=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bukkit/compatibility/BukkitCompatibilityManager.java | 2 +- .../quickshop/QuickShopItemExpressionHandler.java | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) 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 79df69a97..2e17e977f 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 @@ -143,7 +143,7 @@ public class BukkitCompatibilityManager implements CompatibilityManager { logHook("ModelEngine"); } if (this.isPluginEnabled("QuickShop-Hikari")) { - new QuickShopItemExpressionHandler(this.plugin); + new QuickShopItemExpressionHandler(this.plugin).register(); logHook("QuickShop-Hikari"); } } diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java index 148dafeaa..0eb528a33 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/quickshop/QuickShopItemExpressionHandler.java @@ -22,8 +22,6 @@ public class QuickShopItemExpressionHandler implements ItemExpressionHandler, Li public QuickShopItemExpressionHandler(BukkitCraftEngine plugin) { this.plugin = plugin; - Bukkit.getPluginManager().registerEvents(this, plugin.javaPlugin()); - register(); } public void register() { @@ -32,11 +30,6 @@ public class QuickShopItemExpressionHandler implements ItemExpressionHandler, Li itemExpressionRegistry.registerHandlerSafely(this); } - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - public void onQuickShopReload(final QSConfigurationReloadEvent event) { - register(); - } - @Override public @NotNull Plugin getPlugin() { return this.plugin.javaPlugin(); From 7976b3a64d0ac272e87764e0c695969c095909ab Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 23:39:37 +0800 Subject: [PATCH 124/125] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=88=86=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../default/configuration/blocks/palm_tree.yml | 5 ++++- .../allocator/VisualBlockStateAllocator.java | 17 ++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml index 6002d41ac..1e2e8afd7 100644 --- a/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml +++ b/common-files/src/main/resources/resources/default/configuration/blocks/palm_tree.yml @@ -154,6 +154,9 @@ items: fuel-time: 100 data: item-name: + lore: + - "Requires the datapack tree configuration to function." + - "If not configured, an oak tree will grow by default." model: template: default:model/generated arguments: @@ -171,7 +174,7 @@ items: - minecraft:farmland - minecraft:sand - type: sapling_block - feature: minecraft:fancy_oak + feature: minecraft:fancy_oak # use custom tree configuration here bone-meal-success-chance: 0.45 loot: template: default:loot_table/self diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java index 7087b55d2..9c729bc97 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/allocator/VisualBlockStateAllocator.java @@ -91,6 +91,7 @@ public class VisualBlockStateAllocator { // 如果候选满足组,那么直接允许起飞 if (pair.left().test(candidate.blockState())) { pair.right().complete(candidate.blockState()); + candidate.setUsed(); } else { // 不满足候选组要求,那就等着分配新的吧 } @@ -109,13 +110,15 @@ public class VisualBlockStateAllocator { for (AutoStateGroup group : AutoStateGroup.values()) { List>> pendingAllocationFuture = this.pendingAllocationFutures[group.ordinal()]; for (Pair> pair : pendingAllocationFuture) { - BlockStateCandidate nextCandidate = group.findNextCandidate(); - if (nextCandidate != null) { - nextCandidate.setUsed(); - this.cachedBlockStates.put(pair.left(), nextCandidate.blockState()); - pair.right().complete(nextCandidate.blockState()); - } else { - pair.right().completeExceptionally(new StateExhaustedException(group)); + if (!pair.right().isDone()) { + BlockStateCandidate nextCandidate = group.findNextCandidate(); + if (nextCandidate != null) { + nextCandidate.setUsed(); + this.cachedBlockStates.put(pair.left(), nextCandidate.blockState()); + pair.right().complete(nextCandidate.blockState()); + } else { + pair.right().completeExceptionally(new StateExhaustedException(group)); + } } } } From 560efd90aefd941ef7bebfe20543ab61c7a7533b Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Mon, 6 Oct 2025 23:46:19 +0800 Subject: [PATCH 125/125] Update gradle.properties --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 2b0c372b7..0623c52af 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.63.11 +project_version=0.0.64 config_version=47 lang_version=33 project_group=net.momirealms