package me.modmuss50.optifabric.mod; import com.chocohead.mm.api.ClassTinkerers; import me.modmuss50.optifabric.patcher.ClassCache; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.metadata.ModMetadata; import net.fabricmc.loader.util.version.SemanticVersionImpl; import net.fabricmc.loader.util.version.SemanticVersionPredicateParser; import net.fabricmc.loader.util.version.VersionParsingException; import org.apache.commons.lang3.tuple.Pair; import org.spongepowered.asm.mixin.Mixins; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Predicate; @SuppressWarnings("unused") public class OptifabricSetup implements Runnable { public static final String OPTIFABRIC_INCOMPATIBLE = "optifabric:incompatible"; public static File optifineRuntimeJar = null; //This is called early on to allow us to get the transformers in beofore minecraft starts @Override public void run() { if(!validateLoaderVersion()) return; if(!validateMods()) return; try { OptifineSetup optifineSetup = new OptifineSetup(); Pair<File, ClassCache> runtime = optifineSetup.getRuntime(); //Add the optifine jar to the classpath, as ClassTinkerers.addURL(runtime.getLeft().toURI().toURL()); OptifineInjector injector = new OptifineInjector(runtime.getRight()); injector.setup(); optifineRuntimeJar = runtime.getLeft(); } catch (Throwable e) { if(!OptifabricError.hasError()){ OptifineVersion.jarType = OptifineVersion.JarType.INCOMPATIBE; OptifabricError.setError("Failed to load optifine, check the log for more info \n\n " + e.getMessage()); } throw new RuntimeException("Failed to setup optifine", e); } if(FabricLoader.getInstance().isModLoaded("fabric-renderer-indigo")){ validateIndigoVersion(); Mixins.addConfiguration("optifabric.indigofix.mixins.json"); } Mixins.addConfiguration("optifabric.optifine.mixins.json"); } //I check the version like this as I want to show issues on our error screen private void validateIndigoVersion() { try { if (!isVersionValid("fabric-renderer-indigo", ">=0.1.8")) { if(!OptifabricError.hasError()){ OptifineVersion.jarType = OptifineVersion.JarType.INCOMPATIBE; OptifabricError.setError("You are using an outdated version of Fabric (API), please update!\n\nDownload the jar from the link bellow and replace the existing Fabric (API) jar in your mods folder.", "https://www.curseforge.com/minecraft/mc-mods/fabric-api/files"); OptifabricError.setHelpButtonText("Download Fabric (API)"); } } } catch (Throwable e){ if(!OptifabricError.hasError()){ OptifineVersion.jarType = OptifineVersion.JarType.INCOMPATIBE; OptifabricError.setError("Failed to load optifine, check the log for more info \n\n " + e.getMessage()); } throw new RuntimeException("Failed to setup optifine", e); } } private boolean validateMods() { List<ModMetadata> incompatibleMods = new ArrayList<>(); for (ModContainer container : FabricLoader.getInstance().getAllMods()) { ModMetadata metadata = container.getMetadata(); if(metadata.containsCustomValue(OPTIFABRIC_INCOMPATIBLE)) { incompatibleMods.add(metadata); } } if (!incompatibleMods.isEmpty()) { OptifineVersion.jarType = OptifineVersion.JarType.INCOMPATIBE; StringBuilder errorMessage = new StringBuilder("One or more mods have stated they are incompatible with OptiFabric\nPlease remove OptiFabric or the following mods:\n"); for (ModMetadata metadata : incompatibleMods) { errorMessage.append(metadata.getName()) .append(" (") .append(metadata.getId()) .append(")\n"); } OptifabricError.setError(errorMessage.toString()); } return incompatibleMods.isEmpty(); } private boolean validateLoaderVersion() { try { if (!isVersionValid("fabricloader", ">=0.7.0")) { if(!OptifabricError.hasError()){ OptifineVersion.jarType = OptifineVersion.JarType.INCOMPATIBE; OptifabricError.setError("You are using an outdated version of Fabric Loader, please update!\n\nRe-run the installer, or update via your launcher. See the link for help!", "https://fabricmc.net/wiki/install"); OptifabricError.setHelpButtonText("Installation Instructions"); return false; } } } catch (Throwable e){ if(!OptifabricError.hasError()){ OptifineVersion.jarType = OptifineVersion.JarType.INCOMPATIBE; OptifabricError.setError("Failed to load optifine, check the log for more info \n\n " + e.getMessage()); } throw new RuntimeException("Failed to setup optifine", e); } return true; } private boolean isVersionValid(String modID, String validVersion) throws VersionParsingException { ModMetadata modMetadata = getModMetaData(modID); if(modMetadata == null) { throw new RuntimeException(String.format("Failed to get mod container for %s, something has broke badly.", modID)); } Predicate<SemanticVersionImpl> predicate = SemanticVersionPredicateParser.create(validVersion); SemanticVersionImpl version = new SemanticVersionImpl(modMetadata.getVersion().getFriendlyString(), false); return predicate.test(version); } private ModMetadata getModMetaData(String modId) { Optional<ModContainer> modContainer = FabricLoader.getInstance().getModContainer(modId); return modContainer.map(ModContainer::getMetadata).orElse(null); } }