package me.modmuss50.optifabric.mod; import com.google.gson.Gson; import com.google.gson.JsonObject; import me.modmuss50.optifabric.patcher.ASMUtils; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.client.main.Main; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.FieldNode; import org.zeroturnaround.zip.ZipUtil; import java.io.*; import java.util.jar.JarEntry; import java.util.jar.JarFile; public class OptifineVersion { public static String version; public static String minecraftVersion; public static JarType jarType; public static File findOptifineJar() throws IOException { File modsDir = new File(FabricLoader.getInstance().getGameDirectory(), "mods"); File[] mods = modsDir.listFiles(); File optifineJar = null; if (mods != null) { for (File file : mods) { if (file.isDirectory()) { continue; } if (file.getName().endsWith(".jar")) { JarType type = getJarType(file); if (type.error) { throw new RuntimeException("An error occurred when trying to find the optifine jar: " + type.name()); } if (type == JarType.OPIFINE_MOD || type == JarType.OPTFINE_INSTALLER) { if(optifineJar != null){ OptifabricError.setError("Found 2 or more optifine jars, please ensure you only have 1 copy of optifine in the mods folder!"); throw new FileNotFoundException("Multiple optifine jars"); } jarType = type; optifineJar = file; } } } } if(optifineJar != null){ return optifineJar; } OptifabricError.setError("OptiFabric could not find the Optifine jar in the mods folder."); throw new FileNotFoundException("Could not find optifine jar"); } private static JarType getJarType(File file) throws IOException { ClassNode classNode; try (JarFile jarFile = new JarFile(file)) { JarEntry jarEntry = jarFile.getJarEntry("net/optifine/Config.class"); // New 1.14.3 location if (jarEntry == null) { return JarType.SOMETHINGELSE; } classNode = ASMUtils.asClassNode(jarEntry, jarFile); } for (FieldNode fieldNode : classNode.fields) { if (fieldNode.name.equals("VERSION")) { version = (String) fieldNode.value; } if (fieldNode.name.equals("MC_VERSION")) { minecraftVersion = (String) fieldNode.value; } } if (version == null || version.isEmpty() || minecraftVersion == null || minecraftVersion.isEmpty()) { return JarType.INCOMPATIBE; } String currentMcVersion = "unknown"; try { try(InputStream is = OptifineVersion.class.getResourceAsStream("/version.json")){ try(InputStreamReader isr = new InputStreamReader(is)){ JsonObject jsonObject = new Gson().fromJson(isr, JsonObject.class); currentMcVersion = jsonObject.get("name").getAsString(); } } } catch (Exception e){ OptifabricError.setError("Failed to find minecraft version"); e.printStackTrace(); return JarType.INCOMPATIBE; } if (!currentMcVersion.equals(minecraftVersion)) { OptifabricError.setError(String.format("This version of optifine is not compatible with the current minecraft version\n\n Optifine requires %s you have %s", minecraftVersion, currentMcVersion)); return JarType.INCOMPATIBE; } Holder<Boolean> isInstaller = new Holder<>(false); ZipUtil.iterate(file, (in, zipEntry) -> { if (zipEntry.getName().startsWith("patch/")) { isInstaller.setValue(true); } }); if (isInstaller.getValue()) { return JarType.OPTFINE_INSTALLER; } else { return JarType.OPIFINE_MOD; } } public enum JarType { OPIFINE_MOD(false), OPTFINE_INSTALLER(false), INCOMPATIBE(true), SOMETHINGELSE(false); boolean error; JarType(boolean error) { this.error = error; } public boolean isError() { return error; } } private static class Holder<T> { T value; private Holder(T value) { this.value = value; } public T getValue() { return value; } public void setValue(T value) { this.value = value; } public static <T> Holder<T> of(T value) { return new Holder<>(value); } } }