Skip to content

Commit

Permalink
Better mixin infrastructure
Browse files Browse the repository at this point in the history
  • Loading branch information
JL2210 committed Aug 3, 2024
1 parent 0e16c68 commit 81a11c4
Show file tree
Hide file tree
Showing 15 changed files with 302 additions and 44 deletions.
23 changes: 23 additions & 0 deletions src/main/java/me/eigenraven/lwjgl3ify/Lwjgl3ifyLateMixins.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package me.eigenraven.lwjgl3ify;

import java.util.List;
import java.util.Set;

import com.gtnewhorizon.gtnhmixins.ILateMixinLoader;
import com.gtnewhorizon.gtnhmixins.LateMixin;

import me.eigenraven.lwjgl3ify.mixins.Mixins;

@LateMixin
public class Lwjgl3ifyLateMixins implements ILateMixinLoader {

@Override
public String getMixinConfig() {
return "mixins.lwjgl3ify.late.json";
}

@Override
public List<String> getMixins(Set<String> loadedMods) {
return Mixins.getLateMixins(loadedMods);
}
}
41 changes: 7 additions & 34 deletions src/main/java/me/eigenraven/lwjgl3ify/core/Lwjgl3ifyCoremod.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package me.eigenraven.lwjgl3ify.core;

import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
Expand All @@ -17,6 +16,7 @@

import cpw.mods.fml.relauncher.FMLLaunchHandler;
import cpw.mods.fml.relauncher.IFMLLoadingPlugin;
import me.eigenraven.lwjgl3ify.mixins.Mixins;

@IFMLLoadingPlugin.MCVersion("1.7.10")
@IFMLLoadingPlugin.SortingIndex(Integer.MAX_VALUE - 2)
Expand Down Expand Up @@ -72,49 +72,22 @@ public String getMixinConfig() {

@Override
public List<String> getMixins(Set<String> loadedCoreMods) {

final boolean hasFastcraft = loadedCoreMods.contains("fastcraft.Tweaker");
final boolean hasOptifine = loadedCoreMods.contains("optifine.OptiFineForgeTweaker");
List<String> mixins = new ArrayList<>(8);
// FML Java 9+ compatibility patches
mixins.add("fml.ItemStackHolderRef");
mixins.add("fml.JarDiscoverer");
mixins.add("fml.ObjectHolderRef");
mixins.add("fml.ObjectHolderRegistry");
if (FMLLaunchHandler.side()
.isClient()) {
// Improved KeyBinding handling to handle dead keys
mixins.add("game.MixinMinecraftKeyBinding");

// Adds the borderless mode
mixins.add("game.MixinBorderlessWindow");

// STB replacements for vanilla functions
if (Config.MIXIN_STBI_TEXTURE_LOADING) {
LOGGER.info("Enabling STB texture loading mixin");
mixins.add("game.MixinTextureAtlasSprite");
mixins.add("game.MixinTextureMap");
} else {
LOGGER.info("Disabling STB texture loading mixin");
}

final boolean hasFastcraft = loadedCoreMods.contains("fastcraft.Tweaker");
final boolean hasOptifine = loadedCoreMods.contains("optifine.OptiFineForgeTweaker");
final boolean fcBugFixedByOF = isFastcraftVersion1_25();
final boolean fcBugTriggered = hasFastcraft && !(hasOptifine && fcBugFixedByOF);
if (fcBugTriggered && !Config.MIXIN_STBI_IGNORE_FASTCRAFT) {
LOGGER.error(
"Not using STB stiching mixins because FastCraft is installed to prevent rapidly flashing screen. Remove FastCraft or "
"Not using STB stitching mixins because FastCraft is installed to prevent rapidly flashing screen. Remove FastCraft or "
+ (!fcBugFixedByOF ? "update to FastCraft 1.25 and " : "")
+ "add OptiFine to enable these performance-improving patches.");
} else {
if (Config.MIXIN_STBI_TEXTURE_STICHING) {
LOGGER.info("Enabling STB texture stitching mixin");
mixins.add("game.MixinStitcher");
} else {
LOGGER.info("Disabling STB texture stitching mixin");
}
Config.MIXIN_STBI_TEXTURE_STICHING = false;
}
}
return mixins;

return Mixins.getEarlyMixins(loadedCoreMods);
}

private static boolean isFastcraftVersion1_25() {
Expand Down
221 changes: 221 additions & 0 deletions src/main/java/me/eigenraven/lwjgl3ify/mixins/Mixins.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package me.eigenraven.lwjgl3ify.mixins;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

import cpw.mods.fml.relauncher.FMLLaunchHandler;
import me.eigenraven.lwjgl3ify.core.Config;
import me.eigenraven.lwjgl3ify.core.Lwjgl3ifyCoremod;

// TODO: have someone who knows what they're doing rewrite these descriptions
public enum Mixins {

// client and server FML Java 9+ compatibility patches
FORGE_JAVA9(new Builder("FML Java 9+ compatibility patch").addTargetedMod(TargetedMod.VANILLA)
.setSide(Side.BOTH)
.setPhase(Phase.EARLY)
.addMixinClasses(
"fml.ItemStackHolderRef",
"fml.JarDiscoverer",
"fml.ObjectHolderRef",
"fml.ObjectHolderRegistry")
.setApplyIf(() -> true)),

// client only
FIX_DEADKEY_KEYBINDING(
new Builder("Improved KeyBinding handling to handle dead keys").addTargetedMod(TargetedMod.VANILLA)
.setSide(Side.CLIENT)
.setPhase(Phase.EARLY)
.addMixinClasses("game.MixinMinecraftKeyBinding")
.setApplyIf(() -> true)),
BORDERLESS_FULLSCREEN(new Builder("Adds the borderless mode").addTargetedMod(TargetedMod.VANILLA)
.setSide(Side.CLIENT)
.setPhase(Phase.EARLY)
.addMixinClasses("game.MixinBorderlessWindow")
.setApplyIf(() -> true)),
STB_LOADING(new Builder("STB texture loading mixin").addTargetedMod(TargetedMod.VANILLA)
.setSide(Side.CLIENT)
.setPhase(Phase.EARLY)
.addMixinClasses("game.MixinTextureAtlasSprite", "game.MixinTextureMap")
.setApplyIf(() -> Config.MIXIN_STBI_TEXTURE_LOADING)),

// the config is disabled in the coremod if the fastcraft bug is triggered
STB_STITCHING(new Builder("STB texture stitching mixin").addTargetedMod(TargetedMod.VANILLA)
.setSide(Side.CLIENT)
.setPhase(Phase.EARLY)
.addMixinClasses("game.MixinStitcher")
.setApplyIf(() -> Config.MIXIN_STBI_TEXTURE_STICHING)); // sic

private final List<String> mixinClasses;
private final List<TargetedMod> targetedMods;
private final List<TargetedMod> excludedMods;
private final Supplier<Boolean> applyIf;
private final Phase phase;
private final Side side;

Mixins(Builder builder) {
this.mixinClasses = builder.mixinClasses;
this.targetedMods = builder.targetedMods;
this.excludedMods = builder.excludedMods;
this.applyIf = builder.applyIf;
this.phase = builder.phase;
this.side = builder.side;
if (this.mixinClasses.isEmpty()) {
throw new RuntimeException("No mixin class specified for Mixin : " + this.name());
}
if (this.targetedMods.isEmpty()) {
throw new RuntimeException("No targeted mods specified for Mixin : " + this.name());
}
if (this.applyIf == null) {
throw new RuntimeException("No ApplyIf function specified for Mixin : " + this.name());
}
if (this.phase == null) {
throw new RuntimeException("No Phase specified for Mixin : " + this.name());
}
if (this.side == null) {
throw new RuntimeException("No Side function specified for Mixin : " + this.name());
}
}

public static List<String> getEarlyMixins(Set<String> loadedCoreMods) {
final List<String> mixins = new ArrayList<>();
final List<String> notLoading = new ArrayList<>();
for (Mixins mixin : Mixins.values()) {
if (mixin.phase == Phase.EARLY) {
if (mixin.shouldLoad(loadedCoreMods, Collections.emptySet())) {
mixins.addAll(mixin.mixinClasses);
} else {
notLoading.addAll(mixin.mixinClasses);
}
}
}
Lwjgl3ifyCoremod.LOGGER.info("Not loading the following EARLY mixins: {}", notLoading.toString());
return mixins;
}

public static List<String> getLateMixins(Set<String> loadedMods) {
// NOTE: Any targetmod here needs a modid, not a coremod id
final List<String> mixins = new ArrayList<>();
final List<String> notLoading = new ArrayList<>();
for (Mixins mixin : Mixins.values()) {
if (mixin.phase == Phase.LATE) {
if (mixin.shouldLoad(Collections.emptySet(), loadedMods)) {
mixins.addAll(mixin.mixinClasses);
} else {
notLoading.addAll(mixin.mixinClasses);
}
}
}
Lwjgl3ifyCoremod.LOGGER.info("Not loading the following LATE mixins: {}", notLoading.toString());
return mixins;
}

private boolean shouldLoadSide() {
return side == Side.BOTH || (side == Side.SERVER && FMLLaunchHandler.side()
.isServer())
|| (side == Side.CLIENT && FMLLaunchHandler.side()
.isClient());
}

private boolean allModsLoaded(List<TargetedMod> targetedMods, Set<String> loadedCoreMods, Set<String> loadedMods) {
if (targetedMods.isEmpty()) return false;

for (TargetedMod target : targetedMods) {
if (target == TargetedMod.VANILLA) continue;

// Check coremod first
if (!loadedCoreMods.isEmpty() && target.coreModClass != null
&& !loadedCoreMods.contains(target.coreModClass)) return false;
else if (!loadedMods.isEmpty() && target.modId != null && !loadedMods.contains(target.modId)) return false;
}

return true;
}

private boolean noModsLoaded(List<TargetedMod> targetedMods, Set<String> loadedCoreMods, Set<String> loadedMods) {
if (targetedMods.isEmpty()) return true;

for (TargetedMod target : targetedMods) {
if (target == TargetedMod.VANILLA) continue;

// Check coremod first
if (!loadedCoreMods.isEmpty() && target.coreModClass != null
&& loadedCoreMods.contains(target.coreModClass)) return false;
else if (!loadedMods.isEmpty() && target.modId != null && loadedMods.contains(target.modId)) return false;
}

return true;
}

private boolean shouldLoad(Set<String> loadedCoreMods, Set<String> loadedMods) {
return (shouldLoadSide() && applyIf.get()
&& allModsLoaded(targetedMods, loadedCoreMods, loadedMods)
&& noModsLoaded(excludedMods, loadedCoreMods, loadedMods));
}

private static class Builder {

private final String name;
private final List<String> mixinClasses = new ArrayList<>();
private final List<TargetedMod> targetedMods = new ArrayList<>();
private final List<TargetedMod> excludedMods = new ArrayList<>();
private Supplier<Boolean> applyIf = null;
private Phase phase = null;
private Side side = null;

public Builder(String name) {
this.name = name;
}

public Builder addMixinClasses(String... mixinClasses) {
this.mixinClasses.addAll(Arrays.asList(mixinClasses));
return this;
}

public Builder setPhase(Phase phase) {
if (this.phase != null) {
throw new RuntimeException("Trying to define Phase twice for " + this.name);
}
this.phase = phase;
return this;
}

public Builder setSide(Side side) {
if (this.side != null) {
throw new RuntimeException("Trying to define Side twice for " + this.name);
}
this.side = side;
return this;
}

public Builder setApplyIf(Supplier<Boolean> applyIf) {
this.applyIf = applyIf;
return this;
}

public Builder addTargetedMod(TargetedMod mod) {
this.targetedMods.add(mod);
return this;
}

public Builder addExcludedMod(TargetedMod mod) {
this.excludedMods.add(mod);
return this;
}
}

private enum Side {
BOTH,
CLIENT,
SERVER
}

private enum Phase {
EARLY,
LATE,
}
}
33 changes: 33 additions & 0 deletions src/main/java/me/eigenraven/lwjgl3ify/mixins/TargetedMod.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package me.eigenraven.lwjgl3ify.mixins;

import cpw.mods.fml.common.Mod;

public enum TargetedMod {

// NOTE: This doesn't work - late mods need a modid, not a coremod class
FASTCRAFT("FastCraft", "fastcraft.Tweaker"),
OPTIFINE("Optifine", "optifine.OptiFineForgeTweaker", "Optifine"),
VANILLA("Minecraft", null);

/** The "name" in the {@link Mod @Mod} annotation */
public final String modName;
/** Class that implements the IFMLLoadingPlugin interface */
public final String coreModClass;
/** The "modid" in the {@link Mod @Mod} annotation */
public final String modId;

TargetedMod(String modName, String coreModClass) {
this(modName, coreModClass, null);
}

TargetedMod(String modName, String coreModClass, String modId) {
this.modName = modName;
this.coreModClass = coreModClass;
this.modId = modId;
}

@Override
public String toString() {
return "TargetedMod{modName='" + modName + "', coreModClass='" + coreModClass + "', modId='" + modId + "'}";
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.eigenraven.lwjgl3ify.mixins.fml;
package me.eigenraven.lwjgl3ify.mixins.early.fml;

import java.lang.reflect.Field;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.eigenraven.lwjgl3ify.mixins.fml;
package me.eigenraven.lwjgl3ify.mixins.early.fml;

import java.util.zip.ZipEntry;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.eigenraven.lwjgl3ify.mixins.fml;
package me.eigenraven.lwjgl3ify.mixins.early.fml;

import java.lang.reflect.Field;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.eigenraven.lwjgl3ify.mixins.fml;
package me.eigenraven.lwjgl3ify.mixins.early.fml;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.eigenraven.lwjgl3ify.mixins.game;
package me.eigenraven.lwjgl3ify.mixins.early.game;

import static org.lwjgl.glfw.GLFW.*;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.eigenraven.lwjgl3ify.mixins.game;
package me.eigenraven.lwjgl3ify.mixins.early.game;

import net.minecraft.client.Minecraft;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.eigenraven.lwjgl3ify.mixins.game;
package me.eigenraven.lwjgl3ify.mixins.early.game;

import java.util.ArrayList;
import java.util.Arrays;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.eigenraven.lwjgl3ify.mixins.game;
package me.eigenraven.lwjgl3ify.mixins.early.game;

import java.awt.image.BufferedImage;

Expand Down
Loading

0 comments on commit 81a11c4

Please sign in to comment.