Skip to content

Instantly share code, notes, and snippets.

@killjoy1221
Created July 11, 2019 23:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save killjoy1221/09f1070aba5e11eb747116340c800536 to your computer and use it in GitHub Desktop.
Save killjoy1221/09f1070aba5e11eb747116340c800536 to your computer and use it in GitHub Desktop.
public class ConfigManager {
private static Set<String> configPaths = new HashSet<>();
private static Map<Object, ConfigInstance> configs = new HashMap<>();
public static <T extends JsonConfig> void register(String path, T config) {
Preconditions.checkState(!configPaths.contains(path), "Duplicate configuration file!");
Preconditions.checkState(!configs.containsKey(config), "Duplicate config instance!");
Path configPath = FabricLoader.getInstance().getConfigDirectory().toPath().resolve(path);
configPaths.add(path);
configs.put(path, new ConfigInstance<>(configPath, config));
try {
try {
load(config);
} catch (NoSuchFileException e) {
save(config);
}
} catch (IOException e) {
LogManager.getLogger().warn("Unable to load config {}", config, e);
}
}
/**
* Used by {@link ConfigScreen} to get the {@link ConfigInstance#valueCache cached values}.
*/
@SuppressWarnings("unchecked")
static <T extends JsonConfig> ConfigInstance<T> getInstance(T config) {
return (ConfigInstance<T>) configs.get(config);
}
public static void load(JsonConfig config) throws IOException {
getInstance(config).load();
}
public static void save(JsonConfig config) throws IOException {
getInstance(config).save();
}
static class ConfigInstance<T extends JsonConfig> {
private final Gson gson;
private final Path configPath;
private final T config;
final Map<String, Value<Object>> valueCache;
private ConfigInstance(Path configPath, T config) {
this.configPath = configPath;
this.config = config;
valueCache = cacheValueObjects();
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(config.getClass(), new TypeAdapter<T>() {
@Override
public void write(JsonWriter out, T value) throws IOException {
out.beginObject();
for (Map.Entry<String, Value<Object>> entry : valueCache.entrySet()) {
out.name(entry.getKey());
Value<?> val = entry.getValue();
gson.toJson(val.get(), val.getDefault().getClass(), out);
}
out.endObject();
}
@Override
public T read(JsonReader in) throws IOException {
in.beginObject();
while (in.hasNext()) {
Value<Object> value = valueCache.get(in.nextName());
if (value == null) {
in.skipValue();
} else {
Object o = gson.fromJson(in, value.getDefault().getClass());
value.set(o);
}
}
in.endObject();
return config;
}
});
config.setupGson(builder);
this.gson = builder.create();
}
/**
* Cache all the values from the config
*/
@SuppressWarnings("unchecked")
private Map<String, Value<Object>> cacheValueObjects() {
try {
Map<String, Value<Object>> map = new TreeMap<>();
for (Field f : config.getClass().getFields()) {
if (f.getType() == Value.class) {
String name = f.getName();
Value<Object> value = (Value<Object>) f.get(config);
map.put(name, value);
}
}
return ImmutableMap.copyOf(map);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private void load() throws IOException {
try (Reader r = Files.newBufferedReader(configPath)) {
gson.fromJson(r, config.getClass());
}
}
private void save() throws IOException {
Files.createDirectories(configPath.getParent());
try (Writer w = Files.newBufferedWriter(configPath)) {
gson.toJson(config, w);
}
}
}
}
public interface JsonConfig {
default void setupGson(GsonBuilder builder) {
}
}
public class Value<T> {
private final T def;
private T value;
public Value(T def) {
this.def = def;
}
public void set(T value) {
this.value = value;
}
public T get() {
return this.value;
}
public T getDefault() {
return def;
}
public void reset() {
set(def);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment