diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java index f79b48f36..9029a35a8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/factory/ComponentItemFactory1_20_5.java @@ -4,11 +4,14 @@ import com.google.gson.JsonElement; import net.momirealms.craftengine.bukkit.item.ComponentItemWrapper; import net.momirealms.craftengine.bukkit.item.ComponentTypes; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MRegistryOps; import net.momirealms.craftengine.bukkit.util.EnchantmentUtils; import net.momirealms.craftengine.core.item.Enchantment; import net.momirealms.craftengine.core.item.Trim; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.util.Key; +import net.momirealms.sparrow.nbt.CompoundTag; import net.momirealms.sparrow.nbt.Tag; import org.bukkit.inventory.ItemStack; @@ -38,29 +41,136 @@ public class ComponentItemFactory1_20_5 extends BukkitItemFactory rootMap = (Map) item.getJavaComponent(ComponentTypes.CUSTOM_DATA).orElse(null); + if (rootMap == null) return null; + Object currentObj = rootMap; + for (int i = 0; i < path.length; i++) { + Object pathSegment = path[i]; + if (pathSegment == null) return null; + String key = pathSegment.toString(); + currentObj = ((Map) currentObj).get(key); + if (currentObj == null) return null; + if (i == path.length - 1) { + return currentObj; + } + if (!(currentObj instanceof Map)) { + return null; + } + } + return currentObj; } @Override protected Tag getNBTTag(ComponentItemWrapper item, Object... path) { - throw new UnsupportedOperationException("This feature is not available on 1.20.5+"); + CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(null); + if (rootTag == null) return null; + Tag currentTag = rootTag; + for (int i = 0; i < path.length; i++) { + Object pathSegment = path[i]; + if (pathSegment == null) return null; + CompoundTag t = (CompoundTag) currentTag; + String key = pathSegment.toString(); + currentTag = t.get(key); + if (currentTag == null) return null; + if (i == path.length - 1) { + return currentTag; + } + if (!(currentTag instanceof CompoundTag)) { + return null; + } + } + return currentTag; } @Override protected void setTag(ComponentItemWrapper item, Object value, Object... path) { - throw new UnsupportedOperationException("This feature is not available on 1.20.5+"); + Tag valueTag; + if (value instanceof Tag tag) { + valueTag = tag; + } else if (value instanceof JsonElement je) { + valueTag = MRegistryOps.JSON.convertTo(MRegistryOps.SPARROW_NBT, je); + } else if (CoreReflections.clazz$Tag.isInstance(value)) { + valueTag = MRegistryOps.NBT.convertTo(MRegistryOps.SPARROW_NBT, value); + } else { + assert MRegistryOps.JAVA != null; + valueTag = MRegistryOps.JAVA.convertTo(MRegistryOps.SPARROW_NBT, value); + } + + CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(new CompoundTag()); + + if (path == null || path.length == 0) { + if (valueTag instanceof CompoundTag) { + rootTag = (CompoundTag) valueTag; + } else { + throw new IllegalArgumentException("Cannot set non-CompoundTag as root without path"); + } + } else { + CompoundTag currentTag = rootTag; + for (int i = 0; i < path.length - 1; i++) { + Object pathSegment = path[i]; + if (pathSegment == null) throw new NullPointerException("Path segment cannot be null"); + + String key = pathSegment.toString(); + Tag nextTag = currentTag.get(key); + + if (!(nextTag instanceof CompoundTag)) { + nextTag = new CompoundTag(); + currentTag.put(key, nextTag); + } + currentTag = (CompoundTag) nextTag; + } + + String finalKey = path[path.length - 1].toString(); + currentTag.put(finalKey, valueTag); + } + + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_DATA, rootTag); } @Override protected boolean hasTag(ComponentItemWrapper item, Object... path) { - throw new UnsupportedOperationException("This feature is not available on 1.20.5+"); + return getNBTTag(item, path) != null; } @Override protected boolean removeTag(ComponentItemWrapper item, Object... path) { - throw new UnsupportedOperationException("This feature is not available on 1.20.5+"); + CompoundTag rootTag = (CompoundTag) item.getSparrowNBTComponent(ComponentTypes.CUSTOM_DATA).orElse(null); + if (rootTag == null || path == null || path.length == 0) return false; + + if (path.length == 1) { + String key = path[0].toString(); + if (rootTag.containsKey(key)) { + rootTag.remove(key); + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_DATA, rootTag); + return true; + } + return false; + } + + CompoundTag parentTag = rootTag; + for (int i = 0; i < path.length - 1; i++) { + Object pathSegment = path[i]; + if (pathSegment == null) return false; + + String key = pathSegment.toString(); + Tag childTag = parentTag.get(key); + + if (!(childTag instanceof CompoundTag)) { + return false; + } + parentTag = (CompoundTag) childTag; + } + + String finalKey = path[path.length - 1].toString(); + if (parentTag.containsKey(finalKey)) { + parentTag.remove(finalKey); + item.setSparrowNBTComponent(ComponentTypes.CUSTOM_DATA, rootTag); + return true; + } + return false; } @Override diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java index 52359827c..9563b71f5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java @@ -2,6 +2,7 @@ package net.momirealms.craftengine.bukkit.plugin.network.handler; import net.momirealms.craftengine.bukkit.item.BukkitItemManager; import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.util.EntityDataUtils; import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; @@ -25,7 +26,8 @@ public class CommonItemPacketHandler implements EntityPacketHandler { for (int i = 0; i < packedItems.size(); i++) { Object packedItem = packedItems.get(i); int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId == EntityDataUtils.ITEM_DATA_ID) { + // TODO 检查为什么会导致问题,难道是其他插件乱发entity id? + if (entityDataId == EntityDataUtils.ITEM_DATA_ID && CoreReflections.clazz$ItemStack.isInstance(packedItem)) { Object nmsItemStack = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); Optional optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user); 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 cce4c9e69..4b62d8f22 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/AbstractFontManager.java @@ -10,7 +10,6 @@ import net.momirealms.craftengine.core.plugin.config.ConfigParser; import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.util.*; import org.ahocorasick.trie.Token; import org.ahocorasick.trie.Trie; @@ -44,10 +43,8 @@ public abstract class AbstractFontManager implements FontManager { protected Trie emojiKeywordTrie; protected Map tagMapper; protected Map emojiMapper; - protected List emojiList; protected List allEmojiSuggestions; - protected Set existingImagePaths = new HashSet<>(); public AbstractFontManager(CraftEngine plugin) { this.plugin = plugin; @@ -68,7 +65,6 @@ public abstract class AbstractFontManager implements FontManager { this.images.clear(); this.illegalChars.clear(); this.emojis.clear(); - this.existingImagePaths.clear(); } @Override @@ -472,14 +468,11 @@ public abstract class AbstractFontManager implements FontManager { if (character.startsWith("\\u")) { chars = List.of(CharacterUtils.decodeUnicodeToChars(character)); } else { - if (CharacterUtils.containsCombinedCharacter(character)) { - TranslationManager.instance().log("warning.config.image.invalid_char", path.toString(), id.toString()); - } - StringBuilder stringBuilder = new StringBuilder(); - for (char c : character.toCharArray()) { - stringBuilder.append(String.format("\\u%04x", (int) c)); - } - chars = List.of(CharacterUtils.decodeUnicodeToChars(stringBuilder.toString())); + // ??? TODO 需要测试特殊字符集 +// if (CharacterUtils.containsCombinedCharacter(character)) { +// TranslationManager.instance().log("warning.config.image.invalid_char", path.toString(), id.toString()); +// } + chars = List.of(character.toCharArray()); } } } @@ -510,30 +503,26 @@ public abstract class AbstractFontManager implements FontManager { } Object heightObj = section.get("height"); - if (!resourceLocation.endsWith(".png")) resourceLocation += ".png"; - Key namespacedPath = Key.of(resourceLocation); - Path targetImagePath = pack.resourcePackFolder() - .resolve("assets") - .resolve(namespacedPath.namespace()) - .resolve("textures") - .resolve(namespacedPath.value()); - - if (!doesImageFileExist(targetImagePath)) { -// TranslationManager.instance().log("warning.config.image.file_not_found", path.toString(), id.toString(), targetImagePath.toString()); - // DO NOT RETURN, JUST GIVE WARNINGS - } else if (heightObj == null) { - try (InputStream in = Files.newInputStream(targetImagePath)) { - BufferedImage image = ImageIO.read(in); - heightObj = image.getHeight() / codepointGrid.length; - } catch (IOException e) { - plugin.logger().warn("Failed to load image " + targetImagePath, e); - return; - } - } if (heightObj == null) { - throw new LocalizedResourceConfigException("warning.config.image.missing_height", path, id); + Key namespacedPath = Key.of(resourceLocation); + Path targetImagePath = pack.resourcePackFolder() + .resolve("assets") + .resolve(namespacedPath.namespace()) + .resolve("textures") + .resolve(namespacedPath.value()); + if (Files.exists(targetImagePath)) { + try (InputStream in = Files.newInputStream(targetImagePath)) { + BufferedImage image = ImageIO.read(in); + heightObj = image.getHeight() / codepointGrid.length; + } catch (IOException e) { + plugin.logger().warn("Failed to load image " + targetImagePath, e); + return; + } + } else { + throw new LocalizedResourceConfigException("warning.config.image.missing_height", path, id); + } } int height = ResourceConfigUtils.getAsInt(heightObj, "height"); @@ -545,22 +534,11 @@ public abstract class AbstractFontManager implements FontManager { BitmapImage bitmapImage = new BitmapImage(id, fontKey, height, ascent, resourceLocation, codepointGrid); for (int[] y : codepointGrid) { for (int x : y) { - font.addBitMapImage(x, bitmapImage); + font.addBitmapImage(x, bitmapImage); } } images.put(id, bitmapImage); } - - private boolean doesImageFileExist(Path path) { - if (existingImagePaths.contains(path)) { - return true; - } - boolean exist = Files.exists(path); - if (exist) { - existingImagePaths.add(path); - } - return exist; - } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/font/Font.java b/core/src/main/java/net/momirealms/craftengine/core/font/Font.java index cfc1cfab9..87ce3b98d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/font/Font.java +++ b/core/src/main/java/net/momirealms/craftengine/core/font/Font.java @@ -28,7 +28,7 @@ public class Font { return this.idToCodepoint.get(codepoint); } - public void addBitMapImage(int codepoint, BitmapImage image) { + public void addBitmapImage(int codepoint, BitmapImage image) { this.idToCodepoint.put(codepoint, image); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java b/core/src/main/java/net/momirealms/craftengine/core/item/AbstractItemManager.java index 1615d4fcb..729fd56b8 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 @@ -439,16 +439,25 @@ public abstract class AbstractItemManager extends AbstractModelGenerator impl }, "external"); registerDataFunction((obj) -> { String name = obj.toString(); - return new CustomNameModifier<>(name); + return new CustomNameModifier<>(Config.nonItalic() ? "" + name : name); }, "custom-name"); registerDataFunction((obj) -> { String name = obj.toString(); - return new ItemNameModifier<>(name); + return new ItemNameModifier<>(Config.nonItalic() ? "" + name : name); }, "item-name", "display-name"); registerDataFunction((obj) -> { - List name = MiscUtils.getAsStringList(obj); - return new LoreModifier<>(name); + List lore = MiscUtils.getAsStringList(obj).stream().map(it -> "" + it).toList(); + return new LoreModifier<>(lore); }, "lore", "display-lore", "description"); + registerDataFunction((obj) -> { + Map> dynamicLore = new LinkedHashMap<>(); + if (obj instanceof Map map) { + for (Map.Entry entry : map.entrySet()) { + dynamicLore.put(entry.getKey().toString(), MiscUtils.getAsStringList(entry.getValue())); + } + } + return new DynamicLoreModifier<>(dynamicLore); + }, "dynamic-lore"); registerDataFunction((obj) -> { Map data = MiscUtils.castToMap(obj, false); return new TagsModifier<>(data); diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java index d16b5281b..6d72273dd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/CustomNameModifier.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; @@ -14,7 +13,7 @@ public class CustomNameModifier implements ItemDataModifier { private final String argument; public CustomNameModifier(String argument) { - this.argument = Config.nonItalic() ? "" + argument : argument; + this.argument = argument; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java new file mode 100644 index 000000000..60c57efb0 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/DynamicLoreModifier.java @@ -0,0 +1,58 @@ +package net.momirealms.craftengine.core.item.modifier; + +import net.momirealms.craftengine.core.item.ComponentKeys; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.ItemBuildContext; +import net.momirealms.craftengine.core.item.NetworkItemHandler; +import net.momirealms.craftengine.core.util.AdventureHelper; +import net.momirealms.craftengine.core.util.VersionHelper; +import net.momirealms.sparrow.nbt.CompoundTag; +import net.momirealms.sparrow.nbt.Tag; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class DynamicLoreModifier implements ItemDataModifier { + private final Map> displayContexts; + private final String defaultContext; + + public DynamicLoreModifier(Map> displayContexts) { + this.defaultContext = displayContexts.keySet().iterator().next(); + this.displayContexts = displayContexts; + } + + @Override + public String name() { + return "dynamic-lore"; + } + + @Override + public void apply(Item item, ItemBuildContext context) { + String displayContext = Optional.ofNullable(item.getJavaTag("craftengine:display_context")).orElse(this.defaultContext).toString(); + List lore = this.displayContexts.get(displayContext); + if (lore == null) { + lore = this.displayContexts.get(this.defaultContext); + } + item.loreComponent(lore.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList()); + } + + @Override + public void prepareNetworkItem(Item item, ItemBuildContext context, CompoundTag networkData) { + if (VersionHelper.isOrAbove1_20_5()) { + Tag previous = item.getNBTComponent(ComponentKeys.LORE); + if (previous != null) { + networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put(ComponentKeys.LORE.asString(), NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } else { + Tag previous = item.getNBTTag("display", "Lore"); + if (previous != null) { + networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.ADD, previous)); + } else { + networkData.put("display.Lore", NetworkItemHandler.pack(NetworkItemHandler.Operation.REMOVE)); + } + } + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java index f59c44abb..081d11a75 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ItemNameModifier.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; @@ -14,7 +13,7 @@ public class ItemNameModifier implements ItemDataModifier { private final String argument; public ItemNameModifier(String argument) { - this.argument = Config.nonItalic() ? "" + argument : argument; + this.argument = argument; } @Override diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java index 6328fe5c8..faeed738c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/LoreModifier.java @@ -4,7 +4,6 @@ import net.momirealms.craftengine.core.item.ComponentKeys; import net.momirealms.craftengine.core.item.Item; import net.momirealms.craftengine.core.item.ItemBuildContext; import net.momirealms.craftengine.core.item.NetworkItemHandler; -import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.VersionHelper; import net.momirealms.sparrow.nbt.CompoundTag; @@ -16,7 +15,7 @@ public class LoreModifier implements ItemDataModifier { private final List argument; public LoreModifier(List argument) { - this.argument = Config.nonItalic() ? argument.stream().map(it -> "" + it).toList() : argument; + this.argument = argument; } @Override @@ -26,8 +25,7 @@ public class LoreModifier implements ItemDataModifier { @Override public void apply(Item item, ItemBuildContext context) { - item.loreComponent(this.argument.stream().map(it -> AdventureHelper.miniMessage().deserialize( - it, context.tagResolvers())).toList()); + item.loreComponent(this.argument.stream().map(it -> AdventureHelper.miniMessage().deserialize(it, context.tagResolvers())).toList()); } @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 d9befc7a4..c2abd2c50 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 @@ -488,6 +488,7 @@ public abstract class AbstractPackManager implements PackManager { this.plugin.logger().info("Loaded packs. Took " + String.format("%.2f", ((o2 - o1) / 1_000_000.0)) + " ms"); for (Map.Entry> entry : cachedConfigs.entrySet()) { ConfigParser parser = entry.getKey(); + if (!predicate.test(parser)) continue; long t1 = System.nanoTime(); for (CachedConfigSection cached : entry.getValue()) { for (Map.Entry configEntry : cached.config().entrySet()) { @@ -497,7 +498,7 @@ public abstract class AbstractPackManager implements PackManager { if (parser.supportsParsingObject()) { // do not apply templates parser.parseObject(cached.pack(), cached.filePath(), id, configEntry.getValue()); - } else if (predicate.test(parser)) { + } else { if (configEntry.getValue() instanceof Map configSection0) { Map config = castToMap(configSection0, false); if ((boolean) config.getOrDefault("enable", 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 4eaecf1f9..6db94681c 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 @@ -160,7 +160,7 @@ public class Config { BasicFileAttributes attributes = Files.readAttributes(this.configFilePath, BasicFileAttributes.class); long lastModified = attributes.lastModifiedTime().toMillis(); long size = attributes.size(); - if (lastModified != this.lastModified || size != this.size) { + if (lastModified != this.lastModified || size != this.size || this.config == null) { byte[] configFileBytes = Files.readAllBytes(this.configFilePath); try (InputStream inputStream = new ByteArrayInputStream(configFileBytes)) { this.config = YamlDocument.create(inputStream); 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 57ef4f95c..398af24f7 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/template/TemplateManagerImpl.java @@ -114,14 +114,14 @@ public class TemplateManagerImpl implements TemplateManager { Map results = new LinkedHashMap<>(); for (Object processedTemplate : processedTemplates) { if (processedTemplate instanceof Map map) { - deepMergeMaps(results, MiscUtils.castToMap(map, false)); + MiscUtils.deepMergeMaps(results, MiscUtils.castToMap(map, false)); } } if (processingResult.overrides() instanceof Map overrides) { results.putAll(MiscUtils.castToMap(overrides, false)); } if (processingResult.merges() instanceof Map merges) { - deepMergeMaps(results, MiscUtils.castToMap(merges, false)); + MiscUtils.deepMergeMaps(results, MiscUtils.castToMap(merges, false)); } return results; } else if (firstTemplate instanceof List) { @@ -155,7 +155,7 @@ public class TemplateManagerImpl implements TemplateManager { if (processingResult.overrides() instanceof Map overrides) { Map output = new LinkedHashMap<>(MiscUtils.castToMap(overrides, false)); if (processingResult.merges() instanceof Map merges) { - deepMergeMaps(output, MiscUtils.castToMap(merges, false)); + MiscUtils.deepMergeMaps(output, MiscUtils.castToMap(merges, false)); } return output; } else if (processingResult.overrides() instanceof List overrides) { @@ -329,28 +329,4 @@ public class TemplateManagerImpl implements TemplateManager { Object merges, Map arguments ) {} - - @SuppressWarnings("unchecked") - private void deepMergeMaps(Map baseMap, Map mapToMerge) { - for (Map.Entry entry : mapToMerge.entrySet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - if (baseMap.containsKey(key)) { - Object existingValue = baseMap.get(key); - if (existingValue instanceof Map && value instanceof Map) { - Map existingMap = (Map) existingValue; - Map newMap = (Map) value; - deepMergeMaps(existingMap, newMap); - } else if (existingValue instanceof List && value instanceof List) { - List existingList = (List) existingValue; - List newList = (List) value; - existingList.addAll(newList); - } else { - baseMap.put(key, value); - } - } else { - baseMap.put(key, value); - } - } - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java index 208625927..90abef1e1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/CharacterUtils.java @@ -11,19 +11,16 @@ public class CharacterUtils { private CharacterUtils() {} public static char[] decodeUnicodeToChars(String unicodeString) { - String processedString = unicodeString.replace("\\u", ""); - int length = processedString.length() / 4; - char[] chars = new char[length]; - for (int i = 0; i < length; i++) { - String hex = processedString.substring(i * 4, i * 4 + 4); + int count = unicodeString.length() / 6; + if (unicodeString.length() % 6 != 0) { + throw new LocalizedResourceConfigException("warning.config.image.invalid_unicode_string_length"); + } + char[] chars = new char[count]; + for (int i = 0, j = 0; j < count; i += 6, j++) { + String hex = unicodeString.substring(i + 2, i + 6); try { int codePoint = Integer.parseInt(hex, 16); - if (Character.isSupplementaryCodePoint(codePoint)) { - chars[i] = Character.highSurrogate(codePoint); - chars[++i] = Character.lowSurrogate(codePoint); - } else { - chars[i] = (char) codePoint; - } + chars[j] = (char) codePoint; } catch (NumberFormatException e) { throw new LocalizedResourceConfigException("warning.config.image.invalid_hex_value", e, hex); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java index bf59ac48f..3cafd6416 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 @@ -99,4 +99,28 @@ public class MiscUtils { } } } + + @SuppressWarnings("unchecked") + public static void deepMergeMaps(Map baseMap, Map mapToMerge) { + for (Map.Entry entry : mapToMerge.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (baseMap.containsKey(key)) { + Object existingValue = baseMap.get(key); + if (existingValue instanceof Map && value instanceof Map) { + Map existingMap = (Map) existingValue; + Map newMap = (Map) value; + deepMergeMaps(existingMap, newMap); + } else if (existingValue instanceof List && value instanceof List) { + List existingList = (List) existingValue; + List newList = (List) value; + existingList.addAll(newList); + } else { + baseMap.put(key, value); + } + } else { + baseMap.put(key, value); + } + } + } } diff --git a/gradle.properties b/gradle.properties index 747826baf..33a71d065 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.56.1 +project_version=0.0.56.2 config_version=34 lang_version=15 project_group=net.momirealms