9
0
mirror of https://github.com/Xiao-MoMi/craft-engine.git synced 2025-12-23 00:49:20 +00:00

新增动态lore

This commit is contained in:
XiaoMoMi
2025-06-07 16:11:37 +08:00
parent c5d471ca0a
commit b0e1305427
15 changed files with 256 additions and 105 deletions

View File

@@ -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<ComponentItemW
return new ComponentItemWrapper(item);
}
@SuppressWarnings("unchecked")
@Override
protected Object getJavaTag(ComponentItemWrapper item, Object... path) {
throw new UnsupportedOperationException("This feature is not available on 1.20.5+");
Map<String, Object> rootMap = (Map<String, Object>) 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<String, Object>) 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

View File

@@ -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<ItemStack> optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user);

View File

@@ -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<String, Component> tagMapper;
protected Map<String, Emoji> emojiMapper;
protected List<Emoji> emojiList;
protected List<String> allEmojiSuggestions;
protected Set<Path> 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;
}
}
}

View File

@@ -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);
}

View File

@@ -439,16 +439,25 @@ public abstract class AbstractItemManager<I> extends AbstractModelGenerator impl
}, "external");
registerDataFunction((obj) -> {
String name = obj.toString();
return new CustomNameModifier<>(name);
return new CustomNameModifier<>(Config.nonItalic() ? "<!i>" + name : name);
}, "custom-name");
registerDataFunction((obj) -> {
String name = obj.toString();
return new ItemNameModifier<>(name);
return new ItemNameModifier<>(Config.nonItalic() ? "<!i>" + name : name);
}, "item-name", "display-name");
registerDataFunction((obj) -> {
List<String> name = MiscUtils.getAsStringList(obj);
return new LoreModifier<>(name);
List<String> lore = MiscUtils.getAsStringList(obj).stream().map(it -> "<!i>" + it).toList();
return new LoreModifier<>(lore);
}, "lore", "display-lore", "description");
registerDataFunction((obj) -> {
Map<String, List<String>> 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<String, Object> data = MiscUtils.castToMap(obj, false);
return new TagsModifier<>(data);

View File

@@ -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<I> implements ItemDataModifier<I> {
private final String argument;
public CustomNameModifier(String argument) {
this.argument = Config.nonItalic() ? "<!i>" + argument : argument;
this.argument = argument;
}
@Override

View File

@@ -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<I> implements ItemDataModifier<I> {
private final Map<String, List<String>> displayContexts;
private final String defaultContext;
public DynamicLoreModifier(Map<String, List<String>> displayContexts) {
this.defaultContext = displayContexts.keySet().iterator().next();
this.displayContexts = displayContexts;
}
@Override
public String name() {
return "dynamic-lore";
}
@Override
public void apply(Item<I> item, ItemBuildContext context) {
String displayContext = Optional.ofNullable(item.getJavaTag("craftengine:display_context")).orElse(this.defaultContext).toString();
List<String> 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<I> 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));
}
}
}
}

View File

@@ -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<I> implements ItemDataModifier<I> {
private final String argument;
public ItemNameModifier(String argument) {
this.argument = Config.nonItalic() ? "<!i>" + argument : argument;
this.argument = argument;
}
@Override

View File

@@ -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<I> implements ItemDataModifier<I> {
private final List<String> argument;
public LoreModifier(List<String> argument) {
this.argument = Config.nonItalic() ? argument.stream().map(it -> "<!i>" + it).toList() : argument;
this.argument = argument;
}
@Override
@@ -26,8 +25,7 @@ public class LoreModifier<I> implements ItemDataModifier<I> {
@Override
public void apply(Item<I> 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

View File

@@ -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<ConfigParser, List<CachedConfigSection>> entry : cachedConfigs.entrySet()) {
ConfigParser parser = entry.getKey();
if (!predicate.test(parser)) continue;
long t1 = System.nanoTime();
for (CachedConfigSection cached : entry.getValue()) {
for (Map.Entry<String, Object> 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<String, Object> config = castToMap(configSection0, false);
if ((boolean) config.getOrDefault("enable", true)) {

View File

@@ -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);

View File

@@ -114,14 +114,14 @@ public class TemplateManagerImpl implements TemplateManager {
Map<String, Object> 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<String, Object> 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<String, TemplateArgument> arguments
) {}
@SuppressWarnings("unchecked")
private void deepMergeMaps(Map<String, Object> baseMap, Map<String, Object> mapToMerge) {
for (Map.Entry<String, Object> 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<String, Object> existingMap = (Map<String, Object>) existingValue;
Map<String, Object> newMap = (Map<String, Object>) value;
deepMergeMaps(existingMap, newMap);
} else if (existingValue instanceof List && value instanceof List) {
List<Object> existingList = (List<Object>) existingValue;
List<Object> newList = (List<Object>) value;
existingList.addAll(newList);
} else {
baseMap.put(key, value);
}
} else {
baseMap.put(key, value);
}
}
}
}

View File

@@ -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);
}

View File

@@ -99,4 +99,28 @@ public class MiscUtils {
}
}
}
@SuppressWarnings("unchecked")
public static void deepMergeMaps(Map<String, Object> baseMap, Map<String, Object> mapToMerge) {
for (Map.Entry<String, Object> 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<String, Object> existingMap = (Map<String, Object>) existingValue;
Map<String, Object> newMap = (Map<String, Object>) value;
deepMergeMaps(existingMap, newMap);
} else if (existingValue instanceof List && value instanceof List) {
List<Object> existingList = (List<Object>) existingValue;
List<Object> newList = (List<Object>) value;
existingList.addAll(newList);
} else {
baseMap.put(key, value);
}
} else {
baseMap.put(key, value);
}
}
}
}

View File

@@ -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