Auto-reload config file on changes (Fabric only)

This commit is contained in:
Jonas Herzig
2021-02-28 00:16:20 +01:00
parent 61d67a5e80
commit 4ca4f2def6

View File

@@ -5,6 +5,8 @@ import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive; import com.google.gson.JsonPrimitive;
import com.replaymod.core.events.SettingsChangedCallback;
import net.minecraft.client.MinecraftClient;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@@ -12,6 +14,11 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.List;
import java.util.Map; import java.util.Map;
import static com.replaymod.core.versions.MCVer.getMinecraft; import static com.replaymod.core.versions.MCVer.getMinecraft;
@@ -27,6 +34,15 @@ class SettingsRegistryBackend {
} }
public void register() { public void register() {
load(true);
try {
registerWatcher();
} catch (IOException e) {
LOGGER.warn("Failed to setup file watcher for {}, live-reloading is disabled. Cause: {}", configFile, e);
}
}
private void load(boolean createIfMissingOrBroken) {
String config; String config;
if (Files.exists(configFile)) { if (Files.exists(configFile)) {
try { try {
@@ -36,14 +52,18 @@ class SettingsRegistryBackend {
return; return;
} }
} else { } else {
save(); if (createIfMissingOrBroken) {
save();
}
return; return;
} }
Gson gson = new Gson(); Gson gson = new Gson();
JsonObject root = gson.fromJson(config, JsonObject.class); JsonObject root = gson.fromJson(config, JsonObject.class);
if (root == null) { if (root == null) {
LOGGER.error("Config file {} appears corrupted: {}", configFile, config); LOGGER.error("Config file {} appears corrupted: {}", configFile, config);
save(); if (createIfMissingOrBroken) {
save();
}
return; return;
} }
for (Map.Entry<SettingsRegistry.SettingKey<?>, Object> entry : settings.entrySet()) { for (Map.Entry<SettingsRegistry.SettingKey<?>, Object> entry : settings.entrySet()) {
@@ -63,12 +83,60 @@ class SettingsRegistryBackend {
entry.setValue(value.getAsNumber().doubleValue()); entry.setValue(value.getAsNumber().doubleValue());
} }
if (key.getDefault() instanceof String && value.isString()) { if (key.getDefault() instanceof String && value.isString()) {
entry.setValue(value.getAsString()); String valueStr = value.getAsString();
if (entry instanceof SettingsRegistry.MultipleChoiceSettingKey) {
@SuppressWarnings("unchecked")
List<String> choices = ((SettingsRegistry.MultipleChoiceSettingKey<String>) entry).getChoices();
if (choices.stream().noneMatch(valueStr::equals)) {
continue;
}
}
entry.setValue(valueStr);
} }
} }
} }
} }
private void registerWatcher() throws IOException {
WatchService watchService = configFile.getFileSystem().newWatchService();
configFile.getParent().register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY);
Thread thread = new Thread(() -> {
while (true) {
WatchKey nextKey;
try {
nextKey = watchService.take();
} catch (InterruptedException e) {
return;
}
for (WatchEvent<?> event : nextKey.pollEvents()) {
WatchEvent.Kind<?> kind = event.kind();
if (kind == StandardWatchEventKinds.OVERFLOW) {
continue;
}
Path fileName = ((Path) event.context());
if (fileName.equals(configFile.getFileName())) {
MinecraftClient.getInstance().send(this::reload);
}
}
if (!nextKey.reset()) {
return;
}
}
});
thread.setName("replaymod-config-watcher");
thread.setDaemon(true);
thread.start();
}
private void reload() {
load(false);
SettingsRegistry settingsRegistry = ReplayMod.instance.getSettingsRegistry();
for (SettingsRegistry.SettingKey<?> key : settings.keySet()) {
SettingsChangedCallback.EVENT.invoker().onSettingsChanged(settingsRegistry, key);
}
}
@SuppressWarnings("unused") @SuppressWarnings("unused")
public void register(SettingsRegistry.SettingKey<?> key) { public void register(SettingsRegistry.SettingKey<?> key) {
} }