From e739beee17f15a97fdd6fec759fe3693088ddce5 Mon Sep 17 00:00:00 2001 From: Maru32768 Date: Thu, 5 Jan 2023 00:01:37 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=AA=E3=83=95=E3=82=A1=E3=82=AF=E3=82=BF?= =?UTF-8?q?=E3=83=AA=E3=83=B3=E3=82=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/kunmc/lab/configlib/BaseConfig.java | 76 +---------- .../java/net/kunmc/lab/testplugin/Config.java | 5 + .../kunmc/lab/configlib/CommonBaseConfig.java | 124 +++++++++++++++--- .../kunmc/lab/configlib/util/ConfigUtil.java | 27 +++- forge/build.gradle | 4 +- .../net/kunmc/lab/configlib/BaseConfig.java | 95 ++------------ .../net/kunmc/lab/samplemod/SampleMod.java | 2 +- 7 files changed, 154 insertions(+), 179 deletions(-) diff --git a/bukkit/src/main/java/net/kunmc/lab/configlib/BaseConfig.java b/bukkit/src/main/java/net/kunmc/lab/configlib/BaseConfig.java index 1073af4..2618ad9 100644 --- a/bukkit/src/main/java/net/kunmc/lab/configlib/BaseConfig.java +++ b/bukkit/src/main/java/net/kunmc/lab/configlib/BaseConfig.java @@ -13,18 +13,13 @@ import org.bukkit.event.server.PluginDisableEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; -import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scoreboard.Team; import org.jetbrains.annotations.NotNull; import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; import java.lang.reflect.Modifier; -import java.nio.file.*; -import java.util.*; - -import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import java.util.Set; +import java.util.TimerTask; public abstract class BaseConfig extends CommonBaseConfig implements Listener { private static final Gson gson = new GsonBuilder().setPrettyPrinting() @@ -44,7 +39,6 @@ public abstract class BaseConfig extends CommonBaseConfig implements Listener { .registerTypeHierarchyAdapter(Set.class, new SetTypeAdapter()) .create(); private final transient Plugin plugin; - private final transient List onInitializeListeners = new ArrayList<>(); public BaseConfig(@NotNull Plugin plugin) { this(plugin, true); @@ -52,52 +46,9 @@ public BaseConfig(@NotNull Plugin plugin) { public BaseConfig(@NotNull Plugin plugin, boolean makeConfigFile) { this.plugin = plugin; + this.makeConfigFile = makeConfigFile; - if (!makeConfigFile) { - return; - } - plugin.getDataFolder() - .mkdir(); - - // コンストラクタの処理内でシリアライズするとフィールドの初期化が終わってない状態でシリアライズされるため遅延させている. - new BukkitRunnable() { - @Override - public void run() { - saveConfigIfAbsent(); - loadConfig(); - onInitializeListeners.forEach(Runnable::run); - } - }.runTask(plugin); - - Timer timer = new Timer(); - WatchService watcher; - WatchKey watchKey; - try { - watcher = FileSystems.getDefault() - .newWatchService(); - watchKey = plugin.getDataFolder() - .toPath() - .register(watcher, ENTRY_MODIFY); - - timer.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - for (WatchEvent e : watchKey.pollEvents()) { - Path filePath = plugin.getDataFolder() - .toPath() - .resolve((Path) e.context()); - if (filePath.equals(getConfigFile().toPath())) { - loadConfig(); - } - } - - watchKey.reset(); - } - }, 0, 500); - } catch (IOException e) { - e.printStackTrace(); - throw new UncheckedIOException(e); - } + init(); // Pluginがenabledになっていない状態でregisterすると例外が発生するため遅延,ループさせている timer.scheduleAtFixedRate(new TimerTask() { @@ -109,13 +60,7 @@ public void run() { @EventHandler public void onPluginDisable(PluginDisableEvent e) { if (e.getPlugin() == plugin) { - try { - timer.cancel(); - watcher.close(); - watchKey.cancel(); - } catch (IOException ex) { - ex.printStackTrace(); - } + close(); } } }, plugin); @@ -126,13 +71,6 @@ public void onPluginDisable(PluginDisableEvent e) { }, 100, 100); } - /** - * set listener fired on initialization. - */ - protected final void onInitialize(Runnable onLoad) { - onInitializeListeners.add(onLoad); - } - public Plugin plugin() { return plugin; } @@ -143,7 +81,7 @@ protected Gson gson() { } @Override - public File getConfigFile() { - return new File(plugin.getDataFolder(), entryName() + ".json"); + File getConfigFolder() { + return plugin.getDataFolder(); } } diff --git a/bukkit/test_plugin/src/main/java/net/kunmc/lab/testplugin/Config.java b/bukkit/test_plugin/src/main/java/net/kunmc/lab/testplugin/Config.java index 26ac968..2efd7bc 100644 --- a/bukkit/test_plugin/src/main/java/net/kunmc/lab/testplugin/Config.java +++ b/bukkit/test_plugin/src/main/java/net/kunmc/lab/testplugin/Config.java @@ -2,6 +2,7 @@ import net.kunmc.lab.configlib.BaseConfig; import net.kunmc.lab.configlib.value.UUIDValue; +import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; @@ -10,5 +11,9 @@ public class Config extends BaseConfig { public Config(@NotNull Plugin plugin) { super(plugin); + + onInitialize(() -> { + Bukkit.broadcastMessage("config initialize"); + }); } } diff --git a/common/src/main/java/net/kunmc/lab/configlib/CommonBaseConfig.java b/common/src/main/java/net/kunmc/lab/configlib/CommonBaseConfig.java index eee4290..0e8c311 100644 --- a/common/src/main/java/net/kunmc/lab/configlib/CommonBaseConfig.java +++ b/common/src/main/java/net/kunmc/lab/configlib/CommonBaseConfig.java @@ -2,6 +2,7 @@ import com.google.common.io.Files; import com.google.gson.Gson; +import net.kunmc.lab.configlib.util.ConfigUtil; import org.codehaus.plexus.util.ReflectionUtils; import org.jetbrains.annotations.NotNull; @@ -14,49 +15,112 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; -import java.util.List; +import java.nio.file.*; +import java.util.*; import java.util.stream.Collectors; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; + public abstract class CommonBaseConfig { protected transient boolean enableGet = true; protected transient boolean enableList = true; protected transient boolean enableModify = true; protected transient boolean enableReload = true; + transient boolean makeConfigFile = true; + private transient volatile boolean initialized = false; private transient String entryName = ""; + private final transient List onInitializeListeners = new ArrayList<>(); + protected final transient Timer timer = new Timer(); + private transient WatchService watchService; + private transient WatchKey watchKey; + + protected CommonBaseConfig() { + String s = getClass().getSimpleName(); + this.entryName = s.substring(0, 1) + .toLowerCase() + s.substring(1); + } protected void setEntryName(@NotNull String entryName) { this.entryName = entryName; } - public String entryName() { - if (entryName.equals("")) { - String n = getClass().getSimpleName(); - return n.substring(0, 1) - .toLowerCase() + n.substring(1); - } else { - return entryName; + public final String entryName() { + return entryName; + } + + final void init() { + if (!makeConfigFile) { + return; + } + getConfigFolder().mkdirs(); + + try { + watchService = FileSystems.getDefault() + .newWatchService(); + watchKey = getConfigFolder().toPath() + .register(watchService, ENTRY_MODIFY); + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + for (WatchEvent e : watchKey.pollEvents()) { + Path filePath = getConfigFolder().toPath() + .resolve((Path) e.context()); + if (filePath.equals(getConfigFile().toPath())) { + loadConfig(); + } + } + watchKey.reset(); + } + }, 0, 500); + } catch (IOException e) { + throw new UncheckedIOException(e); } + + // コンストラクタの処理内でシリアライズすると子クラスのフィールドの初期化が終わってない状態でシリアライズされるため別スレッドでループ待機させている. + timer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + List> values = ConfigUtil.getValues(CommonBaseConfig.this); + if (values.stream() + .allMatch(Objects::nonNull)) { + saveConfigIfAbsent(); + loadConfig(); + cancel(); + } + } + }, 0, 1); + } + + /** + * set listener fired on initialization. + */ + protected final void onInitialize(Runnable onLoad) { + onInitializeListeners.add(onLoad); } - boolean isGetEnabled() { + final boolean isGetEnabled() { return enableGet; } - boolean isListEnabled() { + final boolean isListEnabled() { return enableList; } - boolean isModifyEnabled() { + final boolean isModifyEnabled() { return enableModify; } - boolean isReloadEnabled() { + final boolean isReloadEnabled() { return enableReload; } protected abstract Gson gson(); - public abstract File getConfigFile(); + abstract File getConfigFolder(); + + public final File getConfigFile() { + return new File(getConfigFolder(), entryName() + ".json"); + } protected void saveConfig() { try { @@ -79,21 +143,39 @@ protected void saveConfigIfPresent() { } } - protected boolean loadConfig() { + protected final synchronized boolean loadConfig() { if (!getConfigFile().exists()) { return false; } CommonBaseConfig config = gson().fromJson(readJson(getConfigFile()), this.getClass()); replaceFields(this.getClass(), config, this); + if (!initialized) { + onInitializeListeners.forEach(Runnable::run); + initialized = true; + } return true; } - public static T newInstanceFrom(@NotNull File configJSON, + protected final void close() { + try { + timer.cancel(); + if (watchService != null) { + watchService.close(); + } + if (watchKey != null) { + watchKey.cancel(); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static T newInstanceFrom(@NotNull File jsonFile, @NotNull Constructor constructor, Object... arguments) { - String filename = configJSON.getName(); - String json = readJson(configJSON); + String filename = jsonFile.getName(); + String json = readJson(jsonFile); Class clazz = constructor.getDeclaringClass(); try { @@ -109,7 +191,7 @@ public static T newInstanceFrom(@NotNull File confi } } - protected static String readJson(File jsonFile) { + private static String readJson(File jsonFile) { try { return Files.readLines(jsonFile, StandardCharsets.UTF_8) .stream() @@ -119,7 +201,7 @@ protected static String readJson(File jsonFile) { } } - protected static void writeJson(File jsonFile, String json) { + private static void writeJson(File jsonFile, String json) { try (OutputStreamWriter writer = new OutputStreamWriter(java.nio.file.Files.newOutputStream(jsonFile.toPath()), StandardCharsets.UTF_8)) { writer.write(json); @@ -128,7 +210,7 @@ protected static void writeJson(File jsonFile, String json) { } } - protected static void replaceFields(Class clazz, Object src, Object dst) { + private static void replaceFields(Class clazz, Object src, Object dst) { for (Field field : ReflectionUtils.getFieldsIncludingSuperclasses(clazz)) { if (Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers())) { continue; @@ -149,7 +231,7 @@ protected static void replaceFields(Class clazz, Object src, Object dst) { } } - protected static void replaceField(Field field, Object src, Object dst) throws IllegalAccessException { + private static void replaceField(Field field, Object src, Object dst) throws IllegalAccessException { try { List fieldList = ReflectionUtils.getFieldsIncludingSuperclasses(field.getType()); Object srcObj = field.get(src); diff --git a/common/src/main/java/net/kunmc/lab/configlib/util/ConfigUtil.java b/common/src/main/java/net/kunmc/lab/configlib/util/ConfigUtil.java index 5679ec0..edb0d30 100644 --- a/common/src/main/java/net/kunmc/lab/configlib/util/ConfigUtil.java +++ b/common/src/main/java/net/kunmc/lab/configlib/util/ConfigUtil.java @@ -1,9 +1,6 @@ package net.kunmc.lab.configlib.util; -import net.kunmc.lab.configlib.CollectionValue; -import net.kunmc.lab.configlib.CommonBaseConfig; -import net.kunmc.lab.configlib.MapValue; -import net.kunmc.lab.configlib.SingleValue; +import net.kunmc.lab.configlib.*; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -12,6 +9,15 @@ import java.util.stream.Collectors; public class ConfigUtil { + public static List getValueFields(CommonBaseConfig config) { + return Arrays.stream(config.getClass() + .getDeclaredFields()) + .filter(f -> !Modifier.isStatic(f.getModifiers())) + .filter(f -> Value.class.isAssignableFrom(f.getType())) + .peek(f -> f.setAccessible(true)) + .collect(Collectors.toList()); + } + public static List getSingleValueFields(CommonBaseConfig config) { return Arrays.stream(config.getClass() .getDeclaredFields()) @@ -39,6 +45,19 @@ public static List getMapValueFields(CommonBaseConfig config) { .collect(Collectors.toList()); } + public static List> getValues(CommonBaseConfig config) { + return getValueFields(config).stream() + .map(f -> { + try { + return f.get(config); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + }) + .map(x -> ((SingleValue) x)) + .collect(Collectors.toList()); + } + public static List> getSingleValues(CommonBaseConfig config) { return getSingleValueFields(config).stream() .map(f -> { diff --git a/forge/build.gradle b/forge/build.gradle index 3798e06..725b27d 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -27,6 +27,7 @@ dependencies { implementation group: "org.apache.poi", name: "poi", version: '5.2.2' implementation 'org.codehaus.plexus:plexus-utils:3.5.0' implementation group: "com.google.guava", name: "guava", version: '30.0-android' + implementation 'com.google.code.gson:gson:2.10' compileOnly "com.github.TeamKun.CommandLib:forge:0.11.0" } @@ -35,10 +36,11 @@ shadowJar { include(dependency("org.apache.poi:poi:.*")) include(dependency("org.codehaus.plexus:plexus-utils:.*")) include(dependency("com.google.guava:guava:.*")) + include(dependency("com.google.code.gson:gson:.*")) include(project(":common")) } relocate "org.apache", "${project.group}.${rootProject.name.toLowerCase()}.shadow.org.apache" relocate "org.codehaus", "${project.group}.${rootProject.name.toLowerCase()}.shadow.org.codehaus" - relocate "com.google.guava", "${project.group}.${rootProject.name.toLowerCase()}.shadow.com.google.guava" + relocate "com.google", "${project.group}.${rootProject.name.toLowerCase()}.shadow.com.google" } jar.finalizedBy("shadowJar") diff --git a/forge/src/main/java/net/kunmc/lab/configlib/BaseConfig.java b/forge/src/main/java/net/kunmc/lab/configlib/BaseConfig.java index 206b5a0..8e19860 100644 --- a/forge/src/main/java/net/kunmc/lab/configlib/BaseConfig.java +++ b/forge/src/main/java/net/kunmc/lab/configlib/BaseConfig.java @@ -19,16 +19,11 @@ import org.jetbrains.annotations.NotNull; import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; import java.lang.reflect.Modifier; -import java.nio.file.*; -import java.util.*; +import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; -import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; - public abstract class BaseConfig extends CommonBaseConfig { private static final Gson gson = new GsonBuilder().setPrettyPrinting() .enableComplexMapKeySerialization() @@ -50,10 +45,6 @@ public abstract class BaseConfig extends CommonBaseConfig { .create(); private final transient String modId; private final transient Type type; - private final transient boolean makeConfigFile; - private final transient List onInitializeListeners = new ArrayList<>(); - private transient WatchService watchService; - private transient TimerTask watchTask; public BaseConfig(@NotNull String modId, @NotNull Type type) { this(modId, type, true); @@ -64,11 +55,7 @@ public BaseConfig(@NotNull String modId, @NotNull Type type, boolean makeConfigF this.type = type; this.makeConfigFile = makeConfigFile; - if (ServerLifecycleHooks.getCurrentServer() != null) { - init(); - } else { - MinecraftForge.EVENT_BUS.register(this); - } + MinecraftForge.EVENT_BUS.register(this); } @SubscribeEvent @@ -78,68 +65,15 @@ public void onServerStarting(FMLServerStartingEvent e) { } } - private void init() { - if (!makeConfigFile) { - return; - } - - getConfigFolder().mkdirs(); - new Thread() { - public void run() { - saveConfigIfAbsent(); - loadConfig(); - onInitializeListeners.forEach(Runnable::run); - } - }.start(); - - try { - watchService = FileSystems.getDefault() - .newWatchService(); - WatchKey watchKey = type.getConfigFolder(modId) - .toPath() - .register(watchService, ENTRY_MODIFY); - watchTask = new TimerTask() { - @Override - public void run() { - for (WatchEvent e : watchKey.pollEvents()) { - Path filePath = getConfigFolder().toPath() - .resolve((Path) e.context()); - if (filePath.equals(getConfigFile().toPath())) { - loadConfig(); - } - } - - watchKey.reset(); - } - }; - new Timer().scheduleAtFixedRate(watchTask, 0, 500); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - @SubscribeEvent public void onServerStopping(FMLServerStoppedEvent e) { - if (watchTask != null) { - watchTask.cancel(); - } - if (watchService != null) { - try { - watchService.close(); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } + if (type.shouldClose) { + close(); } } - /** - * set listener fired on initialization. - */ - protected final void onInitialize(Runnable onLoad) { - onInitializeListeners.add(onLoad); - } - - private File getConfigFolder() { + @Override + File getConfigFolder() { return type.getConfigFolder(modId); } @@ -148,20 +82,15 @@ protected Gson gson() { return gson; } - @Override - public File getConfigFile() { - return new File(getConfigFolder(), entryName() + ".json"); - } - public enum Type { COMMON(modId -> { return new File("config/" + modId); - }, () -> true), + }, () -> true, false), CLIENT(modId -> { return new File("config/" + modId); }, () -> { return FMLEnvironment.dist.isClient(); - }), + }, false), SERVER(modId -> { MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); if (server.isDedicatedServer()) { @@ -170,16 +99,16 @@ public enum Type { return new File("saves/" + server.getServerConfiguration() .getWorldName() + "/serverconfig/" + modId); } - }, () -> { - return true; - }); + }, () -> true, true); private final Function getConfigFolder; private final Supplier isCorrectSide; + private final boolean shouldClose; - Type(Function getConfigFolder, Supplier isCorrectSide) { + Type(Function getConfigFolder, Supplier isCorrectSide, boolean shouldClose) { this.getConfigFolder = getConfigFolder; this.isCorrectSide = isCorrectSide; + this.shouldClose = shouldClose; } File getConfigFolder(String modId) { diff --git a/sample/forge/src/main/java/net/kunmc/lab/samplemod/SampleMod.java b/sample/forge/src/main/java/net/kunmc/lab/samplemod/SampleMod.java index 7560c18..4d8c15d 100644 --- a/sample/forge/src/main/java/net/kunmc/lab/samplemod/SampleMod.java +++ b/sample/forge/src/main/java/net/kunmc/lab/samplemod/SampleMod.java @@ -27,7 +27,7 @@ public SampleMod() { MinecraftForge.EVENT_BUS.register(this); } - @SubscribeEvent + @SubscribeEvent(priority = EventPriority.HIGHEST) @OnlyIn(Dist.CLIENT) public void onServerStartingOnClient(FMLServerStartingEvent event) { builder.addConfig(clientConfig);