Skip to content

Commit

Permalink
Experimental/foundation (#16)
Browse files Browse the repository at this point in the history
* Update MixinBooter (CleanroomMC#275)

* update mixinbooter

update mixinbooter

* check if the loader loaded

better solutions?

* updates

* merge CleanroomMC/MixinBooter@d8139da,

* updates

* fixs

* fix

* fix

* fixs

* fixs

* fix

* Bump default mixinbooter version

* Update Mixin

* Add Force X11 option

* Avoid oshi crash on Windows

* Workaround for null crash in Context

* Update Mixin

* Bump lwjglxx

* Update lwjglxx

* Update jline

---------

Co-authored-by: arcade_kappa <[email protected]>
  • Loading branch information
Ecdcaeb and kappa-maintainer authored Mar 1, 2025
2 parents 703a4c6 + 088854a commit 102d2dc
Show file tree
Hide file tree
Showing 12 changed files with 339 additions and 69 deletions.
8 changes: 4 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ project(':cleanroom') {

dependencies {
compileOnly "com.cleanroommc:lwjglx:1.0.0"
installer "com.cleanroommc:lwjglxx:1.0.12"
installer "com.cleanroommc:lwjglxx:1.0.16"
lwjglLibraries[0].each {
installer "org.lwjgl:$it:$props.lwjgl_version"
runtimeOnly "org.lwjgl:$it::$lwjglArch"
Expand Down Expand Up @@ -446,8 +446,8 @@ project(':cleanroom') {

installer 'com.ibm.icu:icu4j:76.1'

installer 'org.jline:jline:3.28.0'
installer 'org.jline:jline-native:3.28.0'
installer 'org.jline:jline:3.29.0'
installer 'org.jline:jline-native:3.29.0'

installer 'net.java.jinput:jinput:2.0.10'

Expand Down Expand Up @@ -507,7 +507,7 @@ project(':cleanroom') {


// Mixin
installer 'com.cleanroommc:sponge-mixin:0.20.8+mixin.0.8.7'
installer 'com.cleanroommc:sponge-mixin:0.20.10+mixin.0.8.7'
installer annotationProcessor('io.github.llamalad7:mixinextras-common:0.5.0-beta.5')

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ public class ForgeEarlyConfig {
public static boolean WINDOW_START_FOCUSED = true;
public static boolean WINDOW_START_ICONIFIED = false;

@Config.Comment("Enable this when the game has problem running on Wayland")
public static boolean FORCE_X11 = false;

public static boolean WINDOW_CENTERED = true;

@Config.Comment("Should the window have decorations (titlebar, border, close button)")
Expand Down Expand Up @@ -56,7 +59,7 @@ public class ForgeEarlyConfig {
public static String COCOA_FRAME_NAME = "minecraft";

public static String CONFIG_ANY_TIME_VERSION = "3.0";
public static String MIXIN_BOOTER_VERSION = "10.2";
public static String MIXIN_BOOTER_VERSION = "10.5";

@Config.Comment("""
Mods in this list have one or more of the problems list below:
Expand Down
61 changes: 47 additions & 14 deletions src/main/java/net/minecraftforge/fml/common/LoadController.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,16 @@
import net.minecraftforge.fml.relauncher.libraries.LibraryManager;
import org.apache.logging.log4j.ThreadContext;
import org.apache.logging.log4j.message.FormattedMessage;

import org.spongepowered.asm.mixin.MixinEnvironment;
import org.spongepowered.asm.mixin.Mixins;
import org.spongepowered.asm.mixin.ModUtil;
import org.spongepowered.asm.mixin.transformer.Config;
import org.spongepowered.asm.mixin.transformer.Proxy;
import org.spongepowered.asm.service.MixinService;
import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper;
import org.spongepowered.asm.util.Constants;
import zone.rong.mixinbooter.Context;
import zone.rong.mixinbooter.ILateMixinLoader;

import javax.annotation.Nullable;
Expand All @@ -52,6 +56,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Supplier;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -165,22 +170,45 @@ public void distributeStateMessage(LoaderState state, Object... eventData)

FMLContextQuery.init(); // Initialize FMLContextQuery and add it to the global list

// Load late mixins
FMLLog.log.info("Instantiating all ILateMixinLoader implemented classes...");
for (ASMDataTable.ASMData asmData : asmDataTable.getAll(ILateMixinLoader.class.getName().replace('.', '/'))) {
modClassLoader.addFile(asmData.getCandidate().getModContainer()); // Add to path before `newInstance`
Class<?> clazz = Class.forName(asmData.getClassName().replace('/', '.'));
FMLLog.log.info("Instantiating {} for its mixins.", clazz);
ILateMixinLoader loader = (ILateMixinLoader) clazz.getConstructor().newInstance();
for (String mixinConfig : loader.getMixinConfigs()) {
if (loader.shouldMixinConfigQueue(mixinConfig)) {
FMLLog.log.info("Adding {} mixin configuration.", mixinConfig);
try {
Mixins.addConfiguration(mixinConfig);
loader.onMixinConfigQueued(mixinConfig);
} catch (Throwable t) {
FMLLog.log.error("Error adding mixin configuration for {}", mixinConfig, t);
try {
modClassLoader.addFile(asmData.getCandidate().getModContainer()); // Add to path before `newInstance`
Class<?> clazz = Class.forName(asmData.getClassName().replace('/', '.'));
FMLLog.log.info("Instantiating {} for its mixins.", clazz);
@SuppressWarnings("deprecation")
ILateMixinLoader loader = (ILateMixinLoader) clazz.getConstructor().newInstance();
for (String mixinConfig : loader.getMixinConfigs()) {
@SuppressWarnings("deprecation")
Context context = new Context(mixinConfig);
if (loader.shouldMixinConfigQueue(context)) {
try {
FMLLog.log.info("Adding {} mixin configuration.", mixinConfig);
Mixins.addConfiguration(mixinConfig);
loader.onMixinConfigQueued(context);
} catch (Throwable t) {
FMLLog.log.error("Error adding mixin configuration for {}", mixinConfig, t);
}
}
}
} catch (ClassNotFoundException | ClassCastException | InstantiationException | IllegalAccessException e) {
FMLLog.log.error("Unable to load the ILateMixinLoader", e);
}
}

// mark config owners : for earlys, lates, and mfAttributes.
for (Config config : Mixins.getConfigs()) {
if (!config.getConfig().hasDecoration(ModUtil.OWNER_DECORATOR)) {
String pkg = config.getConfig().getMixinPackage();
pkg = pkg.charAt(pkg.length() - 1) == '.' ? pkg.substring(0, pkg.length() - 1) : pkg;
List<ModContainer> owners = getPackageOwners(pkg);
if (owners.isEmpty()) {
config.getConfig().decorate(ModUtil.OWNER_DECORATOR, (Supplier) () -> ModUtil.UNKNOWN_OWNER);
} else {
final String owner = owners.get(0).getModId(); // better assign ?
config.getConfig().decorate(ModUtil.OWNER_DECORATOR, (Supplier) () -> owner);
}
}
}

Expand Down Expand Up @@ -421,15 +449,20 @@ private ModContainer findActiveContainerFromStack()
return StackWalker.getInstance()
.walk(frames -> frames.map(StackWalker.StackFrame::getClassName)
.filter(name -> name.lastIndexOf('.') != -1)
.map(name -> name.substring(0, name.lastIndexOf('.')))
.map(pkg -> packageOwners.get(pkg))
.map(name -> packageOwners.get(name.substring(0, name.lastIndexOf('.'))))
.filter(l -> !l.isEmpty())
.findFirst()
.map(List::getFirst)
.orElse(null)
);
}

@Nullable
public List<ModContainer> getPackageOwners(String pkg)
{
return packageOwners.get(pkg);
}

LoaderState getState()
{
return state;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,11 @@ public MixinContainer() {

@Override
public boolean registerBus(EventBus bus, LoadController controller) {
bus.register(this);
return true;
}

@Override
public File getSource()
{
public File getSource() {
return FMLSanityChecker.fmlLocation;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class EventSubscriptionTransformer implements IClassTransformer
{
public EventSubscriptionTransformer()
{
new Event(); // make sure the base event class loaded and initialized.
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import net.minecraft.launchwrapper.LaunchClassLoader;
import net.minecraftforge.fml.relauncher.FMLLaunchHandler;
import org.apache.logging.log4j.LogManager;

import org.spongepowered.asm.launch.GlobalProperties;
import org.spongepowered.asm.launch.MixinBootstrap;

import java.io.File;
Expand All @@ -35,6 +37,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
Expand All @@ -55,6 +58,8 @@ public FMLTweaker()
MixinBootstrap.init();
LogManager.getLogger("FML.TWEAK").info("Initializing MixinExtras...");
MixinExtrasBootstrap.init();

GlobalProperties.put(GlobalProperties.Keys.CLEANROOM_DISABLE_MIXIN_CONFIGS, new HashSet<>());
}
@SuppressWarnings("unchecked")
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
import org.spongepowered.asm.mixin.Mixins;
import org.spongepowered.asm.service.mojang.MixinServiceLaunchWrapper;
import org.spongepowered.asm.util.Constants;
import zone.rong.mixinbooter.IEarlyMixinLoader;
import zone.rong.mixinbooter.IMixinConfigHijacker;

import java.io.*;
import java.net.MalformedURLException;
Expand Down Expand Up @@ -621,6 +623,7 @@ else if (deobfuscatedEnvironment && location == null) // This is probably a mod
FMLPluginWrapper wrap = new FMLPluginWrapper(coreModName, plugin, location, sortIndex, dependencies);
loadPlugins.add(wrap);
FMLLog.log.debug("Enqueued coremod {}", coreModName);
MixinBooterPlugin.queneEarlyMixinLoader(plugin);
return wrap;
}
catch (ClassNotFoundException cnfe)
Expand Down
131 changes: 101 additions & 30 deletions src/main/java/net/minecraftforge/fml/relauncher/MixinBooterPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,34 @@
import net.minecraft.launchwrapper.Launch;
import net.minecraftforge.common.ForgeVersion;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.google.gson.*;

import org.spongepowered.asm.mixin.Mixins;
import org.spongepowered.asm.launch.GlobalProperties;
import zone.rong.mixinbooter.Context;
import zone.rong.mixinbooter.IEarlyMixinLoader;
import zone.rong.mixinbooter.IMixinConfigHijacker;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Set;
import java.util.Map;
import java.util.Enumeration;
import java.io.InputStreamReader;
import java.net.URL;


@SuppressWarnings("deprecation")
@IFMLLoadingPlugin.Name("MixinBooter")
@IFMLLoadingPlugin.MCVersion(ForgeVersion.mcVersion)
@IFMLLoadingPlugin.SortingIndex(1)
public final class MixinBooterPlugin implements IFMLLoadingPlugin {

static Set<IEarlyMixinLoader> earlyMixinLoaders = new HashSet<>();

public MixinBooterPlugin() {
}

Expand All @@ -38,38 +51,96 @@ public String getSetupClass() {

@Override
public void injectData(Map<String, Object> data) {
Object coremodList = data.get("coremodList");
if (coremodList instanceof List) {
Field fmlPluginWrapper$coreModInstance = null;
for (Object coremod : (List) coremodList) {
try {
if (fmlPluginWrapper$coreModInstance == null) {
fmlPluginWrapper$coreModInstance = coremod.getClass().getField("coreModInstance");
fmlPluginWrapper$coreModInstance.setAccessible(true);
}
Object theMod = fmlPluginWrapper$coreModInstance.get(coremod);
if (theMod instanceof IEarlyMixinLoader loader) {
FMLLog.log.info("Grabbing {} for its mixins.", loader.getClass());
for (String mixinConfig : loader.getMixinConfigs()) {
if (loader.shouldMixinConfigQueue(mixinConfig)) {
FMLLog.log.info("Adding {} mixin configuration.", mixinConfig);
Mixins.addConfiguration(mixinConfig);
loader.onMixinConfigQueued(mixinConfig);;
}
}
}
} catch (Throwable t) {
FMLLog.log.error("Unexpected error handling early mixins", t);
}
}
}
loadEarlyLoaders(earlyMixinLoaders);
earlyMixinLoaders = null;
}

@Override
public String getAccessTransformerClass() {
return null;
}

static void queneEarlyMixinLoader(IFMLLoadingPlugin plugin) {
if (plugin instanceof IEarlyMixinLoader earlyMixinLoader) earlyMixinLoaders.add(earlyMixinLoader);
if (plugin instanceof IMixinConfigHijacker hijacker) {
Collection<String> disabledConfigs = GlobalProperties.get(GlobalProperties.Keys.CLEANROOM_DISABLE_MIXIN_CONFIGS);
Context context = new Context(null, Collections.emptySet());
FMLLog.log.info("Loading config hijacker {}.", hijacker.getClass().getName());
for (String hijacked : hijacker.getHijackedMixinConfigs(context)) {
disabledConfigs.add(hijacked);
FMLLog.log.info("{} will hijack the mixin config {}", hijacker.getClass().getName(), hijacked);
}
}
}

private static void loadEarlyLoaders(Collection<IEarlyMixinLoader> queuedLoaders) {
Set<String> modlist = speculatedModList();
for (IEarlyMixinLoader queuedLoader : queuedLoaders) {
FMLLog.log.info("Loading early loader {} for its mixins.", queuedLoader.getClass().getName());
for (String mixinConfig : queuedLoader.getMixinConfigs()) {
Context context = new Context(mixinConfig, modlist);
if (queuedLoader.shouldMixinConfigQueue(context)) {
FMLLog.log.info("Adding {} mixin configuration.", mixinConfig);
Mixins.addConfiguration(mixinConfig);
queuedLoader.onMixinConfigQueued(context);
}
}
}
}

public static Set<String> speculatedModList() {
HashSet<String> presentMods = new HashSet<>();

// buildIn mods :
presentMods.add("minecraft");
presentMods.add("fml");
presentMods.add("forge");
presentMods.add("mixinbooter");
presentMods.add("configanytime");

// mcmod.info
try {
Enumeration<URL> resources = Launch.classLoader.getResources("mcmod.info");
while (resources.hasMoreElements()) {
presentMods.addAll(parseMcmodInfo(resources.nextElement()));
}
} catch (Exception e) {
throw new RuntimeException("Failed to gather present mods from mcmod.info (s)", e);
}

// optifine :
if (Launch.classLoader.isClassExist("optifine.OptiFineTweaker")) {
presentMods.add("optifine");
}

return presentMods;

}

private static Set<String> parseMcmodInfo(URL url) {
try {
HashSet<String> ids = new HashSet<>();
JsonElement root = JsonParser.parseReader(new InputStreamReader(url.openStream()));
if (root.isJsonArray()) {
for (JsonElement element : root.getAsJsonArray()) {
if (element.isJsonObject()) {
ids.add(element.getAsJsonObject().get("modid").getAsString());
}
}
} else {
for (JsonElement element : root.getAsJsonObject().get("modList").getAsJsonArray()) {
if (element.isJsonObject()) {
ids.add(element.getAsJsonObject().get("modid").getAsString());
}
}
}
return ids;
} catch (Throwable t) {
FMLLog.log.error("Failed to parse mcmod.info for " + url, t);
}
return Collections.emptySet();
}



}
Loading

0 comments on commit 102d2dc

Please sign in to comment.