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] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=83=A8=E5=88=86=E6=83=85?= =?UTF-8?q?=E5=86=B5=E4=B8=8B=E9=85=8D=E7=BD=AE=E6=9C=AA=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=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