decorate Mixin configs, fix extension invocation for references
All checks were successful
Publish to snapshot maven / build (push) Successful in 22s

- closes #13
This commit is contained in:
moehreag 2024-08-06 14:12:17 +02:00
parent a4ab17f5a8
commit 0715c7620d
3 changed files with 54 additions and 24 deletions

View file

@ -7,7 +7,7 @@ plugins {
}
group = "dev.frogmc"
version = "0.0.1-alpha.17"
version = "0.0.1-alpha.18"
repositories {
maven {

View file

@ -1,8 +1,12 @@
package dev.frogmc.frogloader.api.mod;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandleProxies;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Map;
import java.util.function.Consumer;
@ -73,10 +77,13 @@ public final class ModExtensions {
@SuppressWarnings({"rawtypes", "unchecked"})
public <T> void runIfPresent(String key, Consumer<T> action) {
Object value = get(key);
if (value instanceof Collection c){
((Collection<T>)c).forEach(action);
} else if (value != null) {
action.accept((T)value);
if (value == null) {
return;
}
if (value instanceof Collection c) {
((Collection<T>) c).forEach(action);
} else {
action.accept((T) value);
}
}
@ -92,37 +99,52 @@ public final class ModExtensions {
* @param action The action to run on the newly retrieved instance of the provided class
* @param <T> The type of the class
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@SuppressWarnings({"unchecked"})
public <T> void runIfPresent(String key, Class<T> type, Consumer<T> action) {
Object value = get(key);
if (value == null) {
return;
}
Consumer<String> c = s -> {
runIfPresent(key, (Consumer<String>) s -> {
try {
MethodHandle handle;
T object;
if (s.contains("::")) {
String[] parts = s.split("::");
handle = MethodHandles.lookup().findVirtual(Class.forName(parts[0]), parts[1], MethodType.methodType(type));
Class<?> extension = Class.forName(parts[0]);
object = (T) handleReference(extension, type, parts[1]);
} else {
handle = MethodHandles.lookup().findConstructor(Class.forName(s), MethodType.methodType(void.class));
object = (T) MethodHandles.lookup().findConstructor(Class.forName(s), MethodType.methodType(void.class)).invoke();
}
T object = (T) handle.invoke();
if (object != null) {
action.accept(object);
}
} catch (Throwable e) {
LOGGER.warn("Failed to instantiate Extension: ", e);
}
};
});
}
if (value instanceof String s) {
c.accept(s);
} else if (value instanceof Collection l) {
((Collection<String>) l).forEach(c);
private Object handleReference(Class<?> clazz, Class<?> type, String ref) throws Throwable {
try {
Field found = clazz.getDeclaredField(ref);
found.setAccessible(true);
return found.get(null);
} catch (Exception ignored) {
}
Method found = null;
for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals(ref)) {
if (found != null) {
throw new IllegalArgumentException("Ambiguous method reference: "+ref+" in "+clazz.getName());
}
found = method;
}
}
if (found != null) {
MethodHandle method = MethodHandles.lookup().unreflect(found);
if (!Modifier.isStatic(found.getModifiers())) {
method = method.bindTo(MethodHandles.lookup().findConstructor(clazz, MethodType.methodType(void.class)).invoke());
}
return MethodHandleProxies.asInterfaceInstance(type, method);
}
throw new IllegalArgumentException("Could not find either a static field or a method named '" + ref + "' in class " + clazz.getName() + "!");
}
}

View file

@ -16,6 +16,7 @@ import dev.frogmc.frogloader.impl.mod.ModDependencyResolver;
import dev.frogmc.frogloader.impl.util.CrashReportGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.asm.mixin.FabricUtil;
import org.spongepowered.asm.mixin.Mixins;
public class PluginLoader {
@ -75,14 +76,21 @@ public class PluginLoader {
@SuppressWarnings({"rawtypes", "unchecked"})
private static void initializeModMixins(Collection<ModProperties> loadedMods) {
Map<String, ModProperties> configs = new HashMap<>();
loadedMods.forEach(props -> {
Object o = props.extensions().get(BuiltinExtensions.MIXIN_CONFIG);
if (o instanceof String name) {
configs.put(name, props);
Mixins.addConfiguration(name);
} else if (o instanceof Collection l) {
((Collection<String>) l).forEach(Mixins::addConfiguration);
((Collection<String>) l).forEach(configFile -> {
configs.put(configFile, props);
Mixins.addConfiguration(configFile);
});
}
});
Mixins.getConfigs().forEach(c ->
c.getConfig().decorate(FabricUtil.KEY_MOD_ID, configs.get(c.getName()).id()));
}
public static GamePlugin discoverGamePlugins() {