package pm.j4.kerosene.util.config; import com.google.common.reflect.TypeToken; import com.google.gson.*; import java.io.*; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Type; import java.util.*; import net.fabricmc.api.ModInitializer; import net.fabricmc.loader.api.FabricLoader; import pm.j4.kerosene.modules.ExampleModule; import pm.j4.kerosene.modules.bindings.BindingInfo; import pm.j4.kerosene.modules.bindings.BindingManager; import pm.j4.kerosene.util.data.ModInfoProvider; import pm.j4.kerosene.util.data.ModuleConfig; import pm.j4.kerosene.util.data.OptionSerializiable; import pm.j4.kerosene.util.module.ModuleBase; /** * The type Config manager. */ public class ConfigManager { /** * The constant GSON. */ public static final Gson GSON = new GsonBuilder() .registerTypeAdapter(GlobalConfig.class, SerializationHelper.getGlobalSerializer()) .registerTypeAdapter(GlobalConfig.class, SerializationHelper.getGlobalDeserializer()) .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).setPrettyPrinting().create(); /** * The constant config. */ private static final Map configs = new HashMap<>(); /** * Prepare config file. * * @param path the path * @param filename the filename * @return the file */ private static File prepareConfigFile(String path, String filename) { if (!Objects.equals(path, "")) { File directory = new File(FabricLoader.getInstance().getConfigDir().toString(), path); if (!directory.exists()) //noinspection ResultOfMethodCallIgnored directory.mkdir(); } return new File(FabricLoader.getInstance().getConfigDir().toString(), path + filename); } /** * Init config. * * @param moduleName the module name */ public static void initConfig(String moduleName, Class parent) { try { Annotation moduleAnnotation = parent.getAnnotation(Modules.class); assert moduleAnnotation != null; Module[] modules = ((Modules)moduleAnnotation).value(); System.out.println(modules); for (int i = 0; i < modules.length; i++) { System.out.println(modules[i].value()); ModInfoProvider.registerMod(modules[i].value()); } } catch (Exception e) { System.out.println(e); } System.out.println("init " + moduleName); if (configs.containsKey(moduleName)) { System.out.println("contains " + configs.get(moduleName)); return; } ConfigHolder config = new ConfigHolder(); config.globalConfig = new DefaultConfig(); config.serverConfigs = new HashMap<>(); System.out.println("load cfg"); config = load(moduleName + "/", moduleName +".json", ConfigHolder.class); initModules(); System.out.println("put cfg"); configs.put(moduleName, config); } /** * Init modules. * */ public static void initModules() { ModInfoProvider.getRegisteredMods().forEach(module -> { System.out.println("module" + module.getModuleName() + " initialized " + module.initialized); if (!module.initialized) { ModuleConfig options = load(module.getParent() + "/modules/", module.getModuleName() + ".json", ModuleConfig.class); System.out.println("initialize " + module.getModuleName()); if (options != null && options.options != null) { options.options.forEach((key, option) -> { if (module.hasOption(option.key)) { System.out.println("setting " + option.key + " to " + option.value.getAsString()); module.setConfigOption(option.key, option.value); } }); } module.initialized = true; } }); } /** * Load. * * @param the type parameter * @param path the path * @param filename the filename * @param tClass the t class * @return the t */ private static T load(String path, String filename, Class tClass) { File file = prepareConfigFile(path, filename); try { if (!file.exists()) { save(path, filename, tClass.newInstance()); } if (file.exists()) { BufferedReader reader = new BufferedReader(new FileReader(file)); T parsedConfig = null; try { parsedConfig = GSON.fromJson(reader, tClass); } catch (Exception e) { System.out.println("Couldn't parse config file"); e.printStackTrace(); } if (parsedConfig != null) { return parsedConfig; } } } catch (FileNotFoundException | InstantiationException | IllegalAccessException e) { System.out.println("Couldn't load configuration file at " + path); e.printStackTrace(); } return null; } /** * Deserialize element t. * * @param the type parameter * @param element the element * @param tClass the t class * @return the t */ public static T deserializeElement(JsonElement element, Class tClass) { return GSON.fromJson(element, tClass); } /** * Save. * * @param the type parameter * @param path the path * @param filename the filename * @param data the data */ private static void save(String path, String filename, T data) { File file = prepareConfigFile(path, filename); String json = GSON.toJson(data); try (FileWriter fileWriter = new FileWriter(file)) { fileWriter.write(json); } catch (IOException e) { System.out.println("Couldn't save configuration file at " + path); e.printStackTrace(); } } /** * Save module. * * @param modName the mod name * @param b the b */ public static void saveModule(String modName, ModuleBase b) { ModuleConfig c = new ModuleConfig(); c.options = GlobalConfig.serializeModuleConfiguration(b); save(modName + "/modules/", b.getModuleName() + ".json", c); } /** * Save all modules. */ public static void saveAllModules() { List mods = ModInfoProvider.getRegisteredMods(); mods.forEach((module) -> ConfigManager.saveModule(module.getParent(), module)); } /** * Save global config. * * @param modName the mod name */ public static void saveGlobalConfig(String modName) { if(configs.containsKey(modName)) { save(modName + "/", modName + ".json", configs.get(modName)); } } public static void saveEverything() { configs.keySet().forEach(key -> { saveGlobalConfig(key); }); saveAllModules(); } /** * Gets config. * * @param modName the mod name * @return the config */ public static Optional getConfig(String modName) { if (configs.containsKey(modName)) { return Optional.of(configs.get(modName)); } return Optional.empty(); } } /** * The type Serialization helper. */ @SuppressWarnings("UnstableApiUsage") class SerializationHelper { /** * The constant s. */ private static final JsonSerializer GLOBAL_CONFIG_JSON_SERIALIZER = (src, typeOfSrc, ctx) -> { JsonObject jsonConfig = new JsonObject(); JsonArray bindings = ctx.serialize(src.serializeBindings()).getAsJsonArray(); jsonConfig.add("bindings", bindings); JsonArray modules = ctx.serialize(src.enabledModules).getAsJsonArray(); jsonConfig.add("enabled_modules", modules); return jsonConfig; }; /** * The constant ds. */ private static final JsonDeserializer GLOBAL_CONFIG_JSON_DESERIALIZER = ((json, typeOfT, ctx) -> { JsonObject obj = json.getAsJsonObject(); List bindings = new ArrayList<>(); if (obj.has("bindings")) { obj.get("bindings").getAsJsonArray().forEach(b -> bindings.add(ctx.deserialize(b, BindingInfo.class))); } List modules = new ArrayList<>(); if (obj.has("enabled_modules")) { obj.get("enabled_modules").getAsJsonArray().forEach(m -> modules.add(m.getAsString())); } GlobalConfig cfg = new GlobalConfig(); Map> options; Type type = new TypeToken>>() { }.getType(); if (obj.has("module_configuration")) { options = ctx.deserialize(obj.get("module_configuration"), type); } else { options = new HashMap<>(); } ModInfoProvider.getRegisteredMods().forEach(module -> { if (options.containsKey(module.getModuleName())) { cfg.deserializeModuleConfiguration(options.get(module.getModuleName()), module); } }); cfg.deserializeBindings(bindings); cfg.enabledModules = modules; return cfg; }); /** * Gets serializer. * * @return the serializer */ public static JsonSerializer getGlobalSerializer() { return GLOBAL_CONFIG_JSON_SERIALIZER; } /** * Gets deserializer. * * @return the deserializer */ public static JsonDeserializer getGlobalDeserializer() { return GLOBAL_CONFIG_JSON_DESERIALIZER; } }