Skip to content

Commit

Permalink
Fix broken classloading under certain conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
Moulberry committed Feb 4, 2025
1 parent 7ff8d39 commit 5c1f8d5
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 68 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ MixinConstraints is available through Maven Central.
__Gradle__
```groovy
dependencies {
include(implementation("com.moulberry:mixinconstraints:1.0.2"))
include(implementation("com.moulberry:mixinconstraints:1.0.4"))
}
```

Expand Down
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
id("com.vanniktech.maven.publish") version("0.28.0") // `maven-publish` doesn't support new maven central
}

version = "1.0.3"
version = "1.0.4"
group = "com.moulberry.mixinconstraints"

idea.module.isDownloadSources = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import net.fabricmc.loader.api.Version;
import net.fabricmc.loader.api.VersionParsingException;

import static com.moulberry.mixinconstraints.util.MixinHacks.unchecked;

public class FabricAbstractionsImpl extends Abstractions {
@Override
protected boolean isDevEnvironment() {
Expand Down Expand Up @@ -36,7 +34,7 @@ protected boolean isVersionInRange(String version, String minVersion, String max
return (min == null || currentVersion.compareTo(min) >= 0) && (max == null || currentVersion.compareTo(max) <= 0);

} catch (VersionParsingException e) {
throw unchecked(e);
throw new RuntimeException(e);
}
}
}
36 changes: 22 additions & 14 deletions src/main/java/com/moulberry/mixinconstraints/MixinConstraints.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@
import org.spongepowered.asm.service.MixinService;

import java.io.IOException;
import java.util.Locale;

import static com.moulberry.mixinconstraints.util.MixinHacks.unchecked;

public class MixinConstraints {

public static final Logger LOGGER = LoggerFactory.getLogger("mixinconstraints");
public static final boolean VERBOSE = "true".equals(System.getProperty("mixinconstraints.verbose"));
public static final Loader LOADER = getLoader();
private static Loader loader = null;

public static boolean shouldApplyMixin(String mixinClassName) {
try {
Expand All @@ -40,17 +37,26 @@ public static boolean shouldApplyMixin(String mixinClassName) {

return true;
} catch (ClassNotFoundException | IOException e) {
throw unchecked(e);
throw new RuntimeException(e);
}
}

private static Loader getLoader() {
if (doesClassExist("net.fabricmc.loader.api.FabricLoader"))
return Loader.FABRIC;
if (doesClassExist("net.minecraftforge.fml.loading.FMLLoader"))
return Loader.FORGE;
if (doesClassExist("net.neoforged.fml.loading.FMLLoader"))
public static Loader getLoader() {
if (loader == null) {
loader = findLoader();
}

return loader;
}

private static Loader findLoader() {
if (doesClassExist("net.neoforged.fml.loading.FMLLoader")) {
return Loader.NEOFORGE;
} else if (doesClassExist("net.minecraftforge.fml.loading.FMLLoader")) {
return Loader.FORGE;
} else if (doesClassExist("net.fabricmc.loader.api.FabricLoader")) {
return Loader.FABRIC;
}

throw new RuntimeException("Could not determine loader");
}
Expand All @@ -69,9 +75,11 @@ public enum Loader {

@Override
public String toString() {
return name().toLowerCase(Locale.ROOT)
.replace("n", "N")
.replace("f", "F");
return switch (this) {
case FORGE -> "Forge";
case NEOFORGE -> "NeoForge";
case FABRIC -> "Fabric";
};
}
}
}
35 changes: 21 additions & 14 deletions src/main/java/com/moulberry/mixinconstraints/util/Abstractions.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,34 @@
import com.moulberry.mixinconstraints.MixinConstraints;

public abstract class Abstractions {
private static final Abstractions instance;
static {
try {
String name = switch(MixinConstraints.LOADER) {
case FORGE -> "com.moulberry.mixinconstraints.ForgeAbstractionsImpl";
case NEOFORGE -> "com.moulberry.mixinconstraints.NeoForgeAbstractionsImpl";
case FABRIC -> "com.moulberry.mixinconstraints.FabricAbstractionsImpl";
};
instance = (Abstractions) Class.forName(name).getDeclaredConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
private static Abstractions instance = null;

private static Abstractions getInstance() {
if (instance == null) {
try {
String name = switch (MixinConstraints.getLoader()) {
case FORGE -> "com.moulberry.mixinconstraints.ForgeAbstractionsImpl";
case NEOFORGE -> "com.moulberry.mixinconstraints.NeoForgeAbstractionsImpl";
case FABRIC -> "com.moulberry.mixinconstraints.FabricAbstractionsImpl";
};
instance = (Abstractions) Class.forName(name).getDeclaredConstructor().newInstance();
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
}
return instance;
}

public static boolean isDevelopmentEnvironment() {
Abstractions instance = getInstance();
return instance.isDevEnvironment();
}

public static boolean isModLoadedWithinVersion(String modId, String minVersion, String maxVersion) {
Abstractions instance = getInstance();

String version = instance.getModVersion(modId);
if(version == null) {
if (version == null) {
return false;
}

Expand Down
70 changes: 36 additions & 34 deletions src/main/java/com/moulberry/mixinconstraints/util/MixinHacks.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,41 +24,49 @@
*/
@SuppressWarnings("unchecked")
public final class MixinHacks {
private static final MethodHandle TARGET_CLASS_CONTEXT_MIXINS;
private static final MethodHandle MIXIN_INFO_GET_STATE;
private static final MethodHandle STATE_CLASS_NODE;
private static MethodHandle TARGET_CLASS_CONTEXT_MIXINS;
private static MethodHandle MIXIN_INFO_GET_STATE;
private static MethodHandle STATE_CLASS_NODE;

private static final MethodHandle EXTENSIONS_EXTENSIONS;
private static final MethodHandle EXTENSIONS_ACTIVE_EXTENSIONS_GET;
private static final MethodHandle EXTENSIONS_ACTIVE_EXTENSIONS_SET;
private static MethodHandle EXTENSIONS_EXTENSIONS;
private static MethodHandle EXTENSIONS_ACTIVE_EXTENSIONS_GET;
private static MethodHandle EXTENSIONS_ACTIVE_EXTENSIONS_SET;

static {
try {
Class<?> TargetClassContext = Class.forName("org.spongepowered.asm.mixin.transformer.TargetClassContext");
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(TargetClassContext, MethodHandles.lookup());
TARGET_CLASS_CONTEXT_MIXINS = lookup.findGetter(TargetClassContext, "mixins", SortedSet.class);
private static boolean initialized = false;

Class<?> MixinInfo = Class.forName("org.spongepowered.asm.mixin.transformer.MixinInfo");
Class<?> MixinInfo$State = Class.forName("org.spongepowered.asm.mixin.transformer.MixinInfo$State");
private static void tryInit() {
if (initialized) {
return;
}
initialized = true;

lookup = MethodHandles.privateLookupIn(MixinInfo, MethodHandles.lookup());
MIXIN_INFO_GET_STATE = lookup.findVirtual(MixinInfo, "getState", MethodType.methodType(MixinInfo$State));
try {
Class<?> TargetClassContext = Class.forName("org.spongepowered.asm.mixin.transformer.TargetClassContext");
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(TargetClassContext, MethodHandles.lookup());
TARGET_CLASS_CONTEXT_MIXINS = lookup.findGetter(TargetClassContext, "mixins", SortedSet.class);

lookup = MethodHandles.privateLookupIn(MixinInfo$State, MethodHandles.lookup());
STATE_CLASS_NODE = lookup.findGetter(MixinInfo$State, "classNode", ClassNode.class);
Class<?> MixinInfo = Class.forName("org.spongepowered.asm.mixin.transformer.MixinInfo");
Class<?> MixinInfo$State = Class.forName("org.spongepowered.asm.mixin.transformer.MixinInfo$State");

lookup = MethodHandles.privateLookupIn(Extensions.class, MethodHandles.lookup());
lookup = MethodHandles.privateLookupIn(MixinInfo, MethodHandles.lookup());
MIXIN_INFO_GET_STATE = lookup.findVirtual(MixinInfo, "getState", MethodType.methodType(MixinInfo$State));

EXTENSIONS_EXTENSIONS = lookup.findGetter(Extensions.class, "extensions", List.class);
EXTENSIONS_ACTIVE_EXTENSIONS_GET = lookup.findGetter(Extensions.class, "activeExtensions", List.class);
EXTENSIONS_ACTIVE_EXTENSIONS_SET = lookup.findSetter(Extensions.class, "activeExtensions", List.class);
lookup = MethodHandles.privateLookupIn(MixinInfo$State, MethodHandles.lookup());
STATE_CLASS_NODE = lookup.findGetter(MixinInfo$State, "classNode", ClassNode.class);

} catch (Throwable e) {
throw unchecked(e);
}
}
lookup = MethodHandles.privateLookupIn(Extensions.class, MethodHandles.lookup());

EXTENSIONS_EXTENSIONS = lookup.findGetter(Extensions.class, "extensions", List.class);
EXTENSIONS_ACTIVE_EXTENSIONS_GET = lookup.findGetter(Extensions.class, "activeExtensions", List.class);
EXTENSIONS_ACTIVE_EXTENSIONS_SET = lookup.findSetter(Extensions.class, "activeExtensions", List.class);

} catch (Throwable e) {
throw new RuntimeException(e);
}
}

public static void registerMixinExtension(IExtension extension) {
tryInit();
try {
Extensions extensions = (Extensions) ((IMixinTransformer) MixinEnvironment.getDefaultEnvironment().getActiveTransformer())
.getExtensions();
Expand All @@ -69,11 +77,12 @@ public static void registerMixinExtension(IExtension extension) {

EXTENSIONS_ACTIVE_EXTENSIONS_SET.invokeExact(extensions, Collections.unmodifiableList(activeExtensions));
} catch (Throwable t) {
throw unchecked(t);
throw new RuntimeException(t);
}
}

public static List<Pair<IMixinInfo, ClassNode>> getMixinsFor(ITargetClassContext context) {
tryInit();
List<Pair<IMixinInfo, ClassNode>> result = new ArrayList<>();
try {
// note: can't use invokeExact here because TargetClassContext is not public
Expand All @@ -82,7 +91,7 @@ public static List<Pair<IMixinInfo, ClassNode>> getMixinsFor(ITargetClassContext
result.add(Pair.of(mixin, classNode));
}
} catch (Throwable e) {
throw unchecked(e);
throw new RuntimeException(e);
}
return result;
}
Expand All @@ -102,11 +111,4 @@ private static void addExtension(List<IExtension> extensions, IExtension newExte
extensions.addAll(lateExtensions);
}

@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException unchecked(Throwable t) throws T {
throw (T) t;
}

private MixinHacks() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ public final class TestMod {

public static void init() {
LOGGER.info("init() called");
LOGGER.info("Platform: {}", MixinConstraints.LOADER);
LOGGER.info("Platform: {}", MixinConstraints.getLoader());
}
}

0 comments on commit 5c1f8d5

Please sign in to comment.