package io.gitlab.jfronny.respackopts.mixin; import com.google.gson.*; import io.gitlab.jfronny.respackopts.Respackopts; import io.gitlab.jfronny.respackopts.data.Respackmeta; import net.minecraft.resource.ResourcePackManager; import net.minecraft.resource.ResourcePackProfile; import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; @Mixin(ResourcePackManager.class) public class ResourcePackManagerMixin { @Shadow private Map profiles; @Inject(at = @At("TAIL"), method = "scanPacks()V") private void scanPacks(CallbackInfo info) { profiles.forEach((s, v) -> { if (respackopts$hasMetadata(v, "conf.json")) { try { Respackmeta conf = Respackopts.g.fromJson(respackopts$readMetadata(v, "conf.json", Respackopts.g), Respackmeta.class); if (!Respackopts.metaVersion.equals(conf.version)) { System.err.println(s + " was not loaded as it specifies a different respackopts version than is installed"); return; } if (!Respackopts.boolVals.containsKey(conf.id)) Respackopts.boolVals.put(conf.id, new HashMap<>()); if (!Respackopts.numVals.containsKey(conf.id)) Respackopts.numVals.put(conf.id, new HashMap<>()); if (!Respackopts.strVals.containsKey(conf.id)) Respackopts.strVals.put(conf.id, new HashMap<>()); if (!Respackopts.enumKeys.containsKey(conf.id)) Respackopts.enumKeys.put(conf.id, new HashMap<>()); Respackopts.resPackMetas.put(v.getDisplayName().asString(), conf); respackopts$registerFields(conf.conf, conf.id, ""); Respackopts.load(conf.id); } catch (Throwable e) { e.printStackTrace(); } } }); } private void respackopts$registerFields(JsonObject data, String id, String keyPrefix) { //Slider if (data.entrySet().stream().allMatch(s -> "default".equals(s.getKey()) || "min".equals(s.getKey()) || "max".equals(s.getKey()))) { JsonElement def = data.get("default"); JsonElement min = data.get("min"); JsonElement max = data.get("max"); if (def.isJsonPrimitive() && def.getAsJsonPrimitive().isNumber() && min.isJsonPrimitive() && min.getAsJsonPrimitive().isNumber() && max.isJsonPrimitive() && max.getAsJsonPrimitive().isNumber()) { double defV = def.getAsNumber().doubleValue(); double minV = min.getAsNumber().doubleValue(); double maxV = max.getAsNumber().doubleValue(); if (defV < minV || defV > maxV) { System.err.println("[respackopts] default value out of range at " + id); } else if (respackopts$isWhole(defV) && respackopts$isWhole(minV) && respackopts$isWhole(maxV)) { Respackopts.numVals.get(id).put(keyPrefix, defV); } else { System.err.println("[respackopts] expected whole number at " + id); } } else { System.err.println("[respackopts] Expected numeric values at " + id); } return; } //Normal object for (Map.Entry entry : data.entrySet()) { String n = ("".equals(keyPrefix) ? "" : keyPrefix + ".") + entry.getKey(); JsonElement e = entry.getValue(); if (e.isJsonPrimitive()) { JsonPrimitive p = e.getAsJsonPrimitive(); if (p.isBoolean()) { if (!Respackopts.boolVals.get(id).containsKey(n)) Respackopts.boolVals.get(id).put(n, p.getAsBoolean()); } else if (p.isNumber()) { if (!Respackopts.numVals.get(id).containsKey(n)) Respackopts.numVals.get(id).put(n, p.getAsDouble()); } else if (p.isString()) { if (!Respackopts.strVals.get(id).containsKey(n)) Respackopts.strVals.get(id).put(n, p.getAsString()); } } else if (e.isJsonArray()) { JsonArray a = e.getAsJsonArray(); for (JsonElement element : a) { if (!element.isJsonPrimitive()) { System.err.println("[respackopts] Unsupported non-primitive datatype"); continue; } if (!Respackopts.enumKeys.get(id).containsKey(n)) { Respackopts.enumKeys.get(id).put(n, new LinkedHashSet<>()); } JsonPrimitive p = element.getAsJsonPrimitive(); if (!p.isString()) { System.err.println("[respackopts] Unsupported non-string enum key"); continue; } String b = p.getAsString(); if (b.contains(":") || b.contains(".") || b.contains("_")) { System.err.println(b + " contains invalid characters"); continue; } Respackopts.enumKeys.get(id).get(n).add(b); } if (!Respackopts.numVals.get(id).containsKey(n)) { Respackopts.numVals.get(id).put(n, 0d); } } else if (e.isJsonNull()) { System.out.println("[respackopts] Config definition contains null, skipping that entry"); } else if (e.isJsonObject()) { respackopts$registerFields(e.getAsJsonObject(), id, n); } else { System.err.println("[respackopts] Unsupported non-primitive datatype"); } } } private boolean respackopts$isWhole(double v) { return v == Math.floor(v) && !Double.isInfinite(v); } private boolean respackopts$hasMetadata(ResourcePackProfile v, String fname) { return v.createResourcePack().contains(ResourceType.CLIENT_RESOURCES, new Identifier(Respackopts.ID, fname)); } private JsonObject respackopts$readMetadata(ResourcePackProfile v, String fname, Gson g) throws IOException { InputStream is = v.createResourcePack().open(ResourceType.CLIENT_RESOURCES, new Identifier(Respackopts.ID, fname)); ByteArrayOutputStream bais = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) != -1) { bais.write(buffer, 0, length); } return g.fromJson(bais.toString(), JsonElement.class).getAsJsonObject(); } }