Skip to content

Commit

Permalink
Update MixinBooter (#275)
Browse files Browse the repository at this point in the history
* update mixinbooter

update mixinbooter

* check if the loader loaded

better solutions?

* updates

* merge CleanroomMC/MixinBooter@d8139da,

* updates

* fixs

* fix

* fix

* fixs

* fixs

* fix
  • Loading branch information
Ecdcaeb authored Feb 14, 2025
1 parent 556959d commit ba492db
Show file tree
Hide file tree
Showing 11 changed files with 332 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,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.3";

@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);
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 ba492db

Please sign in to comment.