diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java index c4d9295ab..5210f9e4a 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/BukkitItemManager.java @@ -365,6 +365,8 @@ public class BukkitItemManager extends AbstractItemManager { // cache command suggestions cachedSuggestions.add(Suggestion.suggestion(id.toString())); + + // TODO Deprecated 理论支持任意物品类型 if (material == Material.TOTEM_OF_UNDYING) cachedTotemSuggestions.add(Suggestion.suggestion(id.toString())); @@ -426,6 +428,7 @@ public class BukkitItemManager extends AbstractItemManager { } if (Config.packMinVersion() < 21.39f) { + // TODO 手动指定旧版格式 List legacyOverridesModels = new ArrayList<>(); processModelRecursively(model, new LinkedHashMap<>(), legacyOverridesModels, materialId, customModelData); TreeSet lom = legacyOverrides.computeIfAbsent(materialId, k -> new TreeSet<>()); 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 9f23ff855..c56a144cf 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 @@ -71,10 +71,11 @@ public abstract class AbstractPackManager implements PackManager { private final BiConsumer eventDispatcher; private final Map loadedPacks = new HashMap<>(); private final Map sectionParsers = new HashMap<>(); - private final TreeMap> cachedConfigs = new TreeMap<>(); protected BiConsumer zipGenerator; protected ResourcePackHost resourcePackHost; + private Map cachedConfigFiles = Collections.emptyMap(); + public AbstractPackManager(CraftEngine plugin, BiConsumer eventDispatcher) { this.plugin = plugin; this.eventDispatcher = eventDispatcher; @@ -175,7 +176,6 @@ public abstract class AbstractPackManager implements PackManager { @Override public void unload() { this.loadedPacks.clear(); - this.cachedConfigs.clear(); } @Override @@ -408,38 +408,48 @@ public abstract class AbstractPackManager implements PackManager { plugin.saveResource("resources/default/resourcepack/assets/minecraft/textures/gui/sprites/tooltip/topaz_frame.png.mcmeta"); } - private void loadResourceConfigs(Predicate predicate) { - long o1 = System.nanoTime(); + private void updateCachedConfigFiles() { + Map previousFiles = this.cachedConfigFiles; + this.cachedConfigFiles = new HashMap<>(); for (Pack pack : loadedPacks()) { if (!pack.enabled()) continue; - Pair, List> files = FileUtils.getConfigsDeeply(pack.configurationFolder()); - for (Path path : files.left()) { - try (InputStreamReader inputStream = new InputStreamReader(new FileInputStream(path.toFile()), StandardCharsets.UTF_8)) { - Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); - Map data = yaml.load(inputStream); - if (data == null) continue; - for (Map.Entry entry : data.entrySet()) { - processConfigEntry(entry, path, pack); + List files = FileUtils.getYmlConfigsDeeply(pack.configurationFolder()); + for (Path path : files) { + CachedConfigFile cachedFile = previousFiles.get(path); + try { + long lastModifiedTime = Files.getLastModifiedTime(path).toMillis(); + if (cachedFile != null && cachedFile.lastModified() == lastModifiedTime) { + this.cachedConfigFiles.put(path, cachedFile); + continue; } - } catch (Exception e) { - this.plugin.logger().warn(path, "Error loading config file", e); + try (InputStreamReader inputStream = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8)) { + Yaml yaml = new Yaml(new StringKeyConstructor(new LoaderOptions())); + Map data = yaml.load(inputStream); + this.cachedConfigFiles.put(path, new CachedConfigFile(data, pack, lastModifiedTime)); + } catch (Exception e) { + this.plugin.logger().warn(path, "Error loading config file", e); + } + } catch (IOException e) { + this.plugin.logger().warn(path, "Error reading last modified time", e); } } - for (Path path : files.right()) { - try (InputStreamReader inputStream = new InputStreamReader(new FileInputStream(path.toFile()), StandardCharsets.UTF_8)) { - Map dataRaw = GsonHelper.get().fromJson(JsonParser.parseReader(inputStream).getAsJsonObject(), Map.class); - Map data = castToMap(dataRaw, false); - for (Map.Entry entry : data.entrySet()) { - processConfigEntry(entry, path, pack); - } - } catch (Exception e) { - this.plugin.logger().warn(path, "Error loading config file", e); - } + } + } + + private void loadResourceConfigs(Predicate predicate) { + TreeMap> cachedConfigs = new TreeMap<>(); + long o1 = System.nanoTime(); + this.updateCachedConfigFiles(); + for (Map.Entry fileEntry : this.cachedConfigFiles.entrySet()) { + CachedConfigFile cachedFile = fileEntry.getValue(); + for (Map.Entry entry : cachedFile.config().entrySet()) { + processConfigEntry(entry, fileEntry.getKey(), cachedFile.pack(), (p, c) -> + cachedConfigs.computeIfAbsent(p, k -> new ArrayList<>()).add(c)); } } 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 : this.cachedConfigs.entrySet()) { + for (Map.Entry> entry : cachedConfigs.entrySet()) { ConfigParser parser = entry.getKey(); long t1 = System.nanoTime(); for (CachedConfig cached : entry.getValue()) { @@ -476,17 +486,17 @@ public abstract class AbstractPackManager implements PackManager { long t2 = System.nanoTime(); this.plugin.logger().info("Loaded " + parser.sectionId()[0] + " in " + String.format("%.2f", ((t2 - t1) / 1_000_000.0)) + " ms"); } - this.cachedConfigs.clear(); } - private void processConfigEntry(Map.Entry entry, Path path, Pack pack) { + private void processConfigEntry(Map.Entry entry, Path path, Pack pack, BiConsumer callback) { if (entry.getValue() instanceof Map typeSections0) { String key = entry.getKey(); int hashIndex = key.indexOf('#'); String configType = hashIndex != -1 ? key.substring(0, hashIndex) : key; Optional.ofNullable(this.sectionParsers.get(configType)) - .ifPresent(parser -> this.cachedConfigs.computeIfAbsent(parser, k -> new ArrayList<>()) - .add(new CachedConfig(key, castToMap(typeSections0, false), path, pack))); + .ifPresent(parser -> { + callback.accept(parser, new CachedConfig(key, castToMap(typeSections0, false), path, pack)); + }); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java new file mode 100644 index 000000000..c39cf4e36 --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/CachedConfigFile.java @@ -0,0 +1,27 @@ +package net.momirealms.craftengine.core.pack; + +import java.util.Map; + +public class CachedConfigFile { + private final Map config; + private final long lastModified; + private final Pack pack; + + public CachedConfigFile(Map config, Pack pack, long lastModified) { + this.config = config; + this.lastModified = lastModified; + this.pack = pack; + } + + public Pack pack() { + return pack; + } + + public Map config() { + return config; + } + + public long lastModified() { + return lastModified; + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java index 0e8889039..a4aec22f6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/FileUtils.java @@ -22,6 +22,31 @@ public class FileUtils { Files.createDirectories(Files.exists(path) ? path.toRealPath() : path); } + public static List getYmlConfigsDeeply(Path configFolder) { + if (!Files.exists(configFolder)) return List.of(); + List validYaml = new ArrayList<>(); + Deque pathDeque = new ArrayDeque<>(); + pathDeque.push(configFolder); + while (!pathDeque.isEmpty()) { + Path path = pathDeque.pop(); + try (DirectoryStream stream = Files.newDirectoryStream(path)) { + for (Path subPath : stream) { + if (Files.isDirectory(subPath)) { + pathDeque.push(subPath); + } else if (Files.isRegularFile(subPath)) { + String pathString = subPath.toString(); + if (pathString.endsWith(".yml")) { + validYaml.add(subPath); + } + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + return validYaml; + } + public static Pair, List> getConfigsDeeply(Path configFolder) { if (!Files.exists(configFolder)) return Pair.of(List.of(), List.of()); List validYaml = new ArrayList<>(); diff --git a/gradle.properties b/gradle.properties index 8a3975c14..6f6eab7d6 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.53.7 +project_version=0.0.53.8 config_version=32 lang_version=12 project_group=net.momirealms