[config] Rework to run without unlocking the classpath (this will require dependents to be updated!)

This commit is contained in:
Johannes Frohnmeyer 2022-04-02 22:01:29 +02:00
parent 76dd6e5df3
commit 900ac479eb
Signed by: Johannes
GPG Key ID: E76429612C2929F4
23 changed files with 120 additions and 76 deletions

View File

@ -27,7 +27,8 @@ allprojects {
dependencies {
modImplementation("com.terraformersmc:modmenu:3.1.0")
modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:${project.fabric_version}")
modRuntimeOnly("net.fabricmc.fabric-api:fabric-api:$project.fabric_version")
modImplementation('io.gitlab.jfronny:gson:2.9.0.2022.4.2.19.45.43')
}
}

View File

@ -3,6 +3,7 @@ minecraft_version=1.18.2
yarn_mappings=build.2
loader_version=0.13.3
fabric_version=0.48.0+1.18.2
maven_group=io.gitlab.jfronny.libjf
archive_base_name=libjf
dev_only_module=libjf-devutil-v0

View File

@ -2,4 +2,5 @@ archivesBaseName = "libjf-base"
dependencies {
include modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "${rootProject.fabric_version}"))
include 'io.gitlab.jfronny:gson:2.9.0.2022.4.2.19.45.43'
}

View File

@ -7,33 +7,32 @@ import org.jetbrains.annotations.ApiStatus;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.function.BiFunction;
@ApiStatus.Internal
public class Flags {
public static Set<StringFlag> getStringFlags(String name) {
Set<StringFlag> flags = new LinkedHashSet<>();
String propName = LibJf.MOD_ID + "." + name;
if (System.getProperty(propName) != null)
flags.add(new StringFlag("System Property", System.getProperty(propName)));
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
if (!mod.getMetadata().containsCustomValue(LibJf.MOD_ID)) continue;
CustomValue.CvObject co = mod.getMetadata().getCustomValue(LibJf.MOD_ID).getAsObject();
if (!co.containsKey(name)) continue;
flags.add(new StringFlag("Mod: " + mod.getMetadata().getId(), co.get(name).getAsString()));
}
return flags;
return getFlags(name,
(source, value) -> new StringFlag(source, value),
(source, value) -> new StringFlag(source, value.getAsString()));
}
public static Set<BooleanFlag> getBoolFlags(String name) {
Set<BooleanFlag> flags = new LinkedHashSet<>();
String propName = LibJf.MOD_ID + "." + name;
return getFlags(name,
(source, value) -> new BooleanFlag(source, true),
(source, value) -> new BooleanFlag(source, value.getAsBoolean()));
}
private static <T> Set<T> getFlags(String name, BiFunction<String, String, T> makeFromProp, BiFunction<String, CustomValue, T> makeFromFmj) {
Set<T> flags = new LinkedHashSet<>();
String propName = "libjf." + name;
if (System.getProperty(propName) != null)
flags.add(new BooleanFlag("System Property", true));
flags.add(makeFromProp.apply("System Property", System.getProperty(propName)));
for (ModContainer mod : FabricLoader.getInstance().getAllMods()) {
if (!mod.getMetadata().containsCustomValue(LibJf.MOD_ID)) continue;
CustomValue.CvObject co = mod.getMetadata().getCustomValue(LibJf.MOD_ID).getAsObject();
if (!mod.getMetadata().containsCustomValue("libjf")) continue;
CustomValue.CvObject co = mod.getMetadata().getCustomValue("libjf").getAsObject();
if (!co.containsKey(name)) continue;
flags.add(new BooleanFlag("Mod: " + mod.getMetadata().getId(), co.get(name).getAsBoolean()));
flags.add(makeFromFmj.apply("Mod: " + mod.getMetadata().getId(), co.get(name)));
}
return flags;
}

View File

@ -1,7 +1,7 @@
package io.gitlab.jfronny.libjf;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.gitlab.jfronny.gson.Gson;
import io.gitlab.jfronny.gson.GsonBuilder;
import io.gitlab.jfronny.libjf.gson.HiddenAnnotationExclusionStrategy;
import io.gitlab.jfronny.libjf.gson.GsonAdapter;
import net.fabricmc.loader.api.FabricLoader;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.interfaces;
package io.gitlab.jfronny.libjf.generic;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.interfaces;
package io.gitlab.jfronny.libjf.generic;
public interface ThrowingRunnable<TEx extends Throwable> {
void run() throws TEx;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.interfaces;
package io.gitlab.jfronny.libjf.generic;
public interface ThrowingSupplier<T, TEx extends Throwable> {
T get() throws TEx;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.interfaces;
package io.gitlab.jfronny.libjf.generic;
import java.util.function.Consumer;
import java.util.function.Function;

View File

@ -1,6 +1,6 @@
package io.gitlab.jfronny.libjf.gson;
import com.google.gson.GsonBuilder;
import io.gitlab.jfronny.gson.GsonBuilder;
public interface GsonAdapter {
GsonBuilder apply(GsonBuilder builder);

View File

@ -1,7 +1,7 @@
package io.gitlab.jfronny.libjf.gson;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import io.gitlab.jfronny.gson.ExclusionStrategy;
import io.gitlab.jfronny.gson.FieldAttributes;
public class HiddenAnnotationExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) {

View File

@ -1,6 +1,6 @@
package io.gitlab.jfronny.libjf.config.api;
import com.google.gson.JsonObject;
import io.gitlab.jfronny.gson.JsonObject;
import io.gitlab.jfronny.libjf.config.impl.EntryInfo;
import java.util.List;

View File

@ -1,5 +1,10 @@
package io.gitlab.jfronny.libjf.config.impl;
import io.gitlab.jfronny.libjf.unsafe.JfLanguageAdapter;
import net.fabricmc.loader.api.metadata.CustomValue;
import net.fabricmc.loader.impl.util.log.Log;
import java.util.LinkedList;
import java.util.List;
public class AuxiliaryMetadata {
@ -7,6 +12,27 @@ public class AuxiliaryMetadata {
public AuxiliaryMetadata sanitize() {
if (referencedConfigs == null) referencedConfigs = List.of();
else referencedConfigs = List.copyOf(referencedConfigs);
return this;
}
public static AuxiliaryMetadata load(CustomValue cv) {
if (cv == null) return null;
AuxiliaryMetadata meta = new AuxiliaryMetadata();
meta.referencedConfigs = new LinkedList<>();
if (cv.getType() == CustomValue.CvType.OBJECT) {
CustomValue.CvObject root = cv.getAsObject();
if (root.containsKey("referencedConfigs")) {
CustomValue referencedConfigs = root.get("referencedConfigs");
if (referencedConfigs.getType() == CustomValue.CvType.ARRAY) {
for (CustomValue value : referencedConfigs.getAsArray()) {
if (value.getType() == CustomValue.CvType.STRING) {
meta.referencedConfigs.add(value.getAsString());
} else Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not load config metadata: referenced config is not a string");
}
} else Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not load config metadata: referencedConfigs is not an array");
}
} else Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not load config metadata: root is not an object");
return meta;
}
}

View File

@ -1,13 +1,15 @@
package io.gitlab.jfronny.libjf.config.impl;
import com.google.common.collect.ImmutableMap;
import com.google.gson.JsonElement;
import io.gitlab.jfronny.gson.Gson;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.api.ConfigHolder;
import io.gitlab.jfronny.libjf.config.api.ConfigInstance;
import io.gitlab.jfronny.libjf.gson.FabricLoaderGsonGenerator;
import io.gitlab.jfronny.libjf.unsafe.JfLanguageAdapter;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.metadata.CustomValue;
import net.fabricmc.loader.impl.util.log.Log;
import org.jetbrains.annotations.ApiStatus;
import java.nio.file.Path;
@ -21,6 +23,7 @@ public class ConfigHolderImpl implements ConfigHolder {
private ConfigHolderImpl() {
}
public static final String MODULE_ID = LibJf.MOD_ID + ":config";
public static final Gson GSON = new Gson();
private final Map<String, ConfigInstance> configs = new HashMap<>();
private final Map<Path, ConfigInstance> configsByPath = new HashMap<>();
@ -28,24 +31,22 @@ public class ConfigHolderImpl implements ConfigHolder {
public void register(String modId, Class<?> config) {
if (isRegistered(modId)) {
if (get(modId).matchesConfigClass(config)) {
LibJf.LOGGER.warn("Attempted to set config of " + modId + " twice, skipping");
Log.warn(JfLanguageAdapter.LOG_CATEGORY, "Attempted to set config of " + modId + " twice, skipping");
return;
}
LibJf.LOGGER.warn("Overriding config class of " + modId + " to " + config);
Log.warn(JfLanguageAdapter.LOG_CATEGORY, "Overriding config class of " + modId + " to " + config);
}
if (isRegistered(config)) {
LibJf.LOGGER.warn("Attempted to reuse config class " + config + ", this is unsupported");
Log.warn(JfLanguageAdapter.LOG_CATEGORY, "Attempted to reuse config class " + config + ", this is unsupported");
}
Optional<ModContainer> container = FabricLoader.getInstance().getModContainer(modId);
AuxiliaryMetadata meta = new AuxiliaryMetadata();
if (container.isPresent()) {
JsonElement el = FabricLoaderGsonGenerator.toGson(container.get().getMetadata().getCustomValue(MODULE_ID));
if (el != null) {
meta = LibJf.GSON.fromJson(el, AuxiliaryMetadata.class);
}
CustomValue cv = container.get().getMetadata().getCustomValue(MODULE_ID);
if (cv != null) meta = AuxiliaryMetadata.load(cv);
}
else {
LibJf.LOGGER.warn("Attempted to register config for a mod that is not installed: " + modId);
Log.warn(JfLanguageAdapter.LOG_CATEGORY, "Attempted to register config for a mod that is not installed: " + modId);
}
ConfigInstanceRoot instance = new ConfigInstanceRoot(modId, config, meta.sanitize());
configs.put(modId, instance);

View File

@ -1,10 +1,11 @@
package io.gitlab.jfronny.libjf.config.impl;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.interfaces.Try;
import io.gitlab.jfronny.gson.JsonElement;
import io.gitlab.jfronny.gson.JsonObject;
import io.gitlab.jfronny.libjf.config.api.*;
import io.gitlab.jfronny.libjf.generic.Try;
import io.gitlab.jfronny.libjf.unsafe.JfLanguageAdapter;
import net.fabricmc.loader.impl.util.log.Log;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
@ -27,7 +28,7 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
this.categoryPath = categoryPath;
this.configClass = configClass;
this.configConstructor = Try.orElse(configClass::getDeclaredConstructor, e -> {
LibJf.LOGGER.error("Could not get constructor for config class of " + modId + ", saving will be unavailable", e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not get constructor for config class of " + modId + ", saving will be unavailable", e);
return null;
});
this.referencedConfigs = List.copyOf(meta.referencedConfigs);
@ -47,7 +48,7 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
try {
entry.field.set(null, entry.defaultValue);
} catch (IllegalAccessException e) {
LibJf.LOGGER.error("Could not reload default values", e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not reload default values", e);
}
}
});
@ -58,7 +59,7 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
try {
method.invoke(null);
} catch (IllegalAccessException | InvocationTargetException e) {
LibJf.LOGGER.error("Could not apply preset", e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not apply preset", e);
}
});
}
@ -67,7 +68,7 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
try {
method.invoke(null);
} catch (IllegalAccessException | InvocationTargetException e) {
LibJf.LOGGER.error("Could not run verifier", e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not run verifier", e);
}
});
}
@ -78,7 +79,7 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
try {
value = entry.field.get(null);
} catch (IllegalAccessException e) {
LibJf.LOGGER.error("Could not read value", e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not read value", e);
continue;
}
final Object valueOriginal = value;
@ -96,7 +97,7 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
try {
entry.field.set(null, value);
} catch (IllegalAccessException e) {
LibJf.LOGGER.error("Could not write value", e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not write value", e);
}
}
}
@ -119,12 +120,12 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
@Override
public void loadObject(JsonObject source) {
LibJf.GSON.fromJson(source, configClass);
ConfigHolderImpl.GSON.fromJson(source, configClass);
for (Map.Entry<String, ConfigInstance> entry : subcategories.entrySet()) {
if (source.has(entry.getKey())) {
JsonElement el = source.get(entry.getKey());
if (el.isJsonObject()) entry.getValue().loadObject(el.getAsJsonObject());
else LibJf.LOGGER.error("Config category is not a JSON object, skipping");
else Log.error(JfLanguageAdapter.LOG_CATEGORY, "Config category is not a JSON object, skipping");
}
}
}
@ -133,10 +134,10 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
public JsonObject writeObject() {
try {
if (configConstructor == null) {
LibJf.LOGGER.error("Could not save config of " + modId + " due to a missing constructor");
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not save config of " + modId + " due to a missing constructor");
return new JsonObject();
}
JsonObject jo = LibJf.GSON.toJsonTree(configConstructor.newInstance()).getAsJsonObject();
JsonObject jo = ConfigHolderImpl.GSON.toJsonTree(configConstructor.newInstance()).getAsJsonObject();
for (Map.Entry<String, ConfigInstance> entry : subcategories.entrySet()) {
jo.add(entry.getKey(), entry.getValue().writeObject());
}
@ -152,7 +153,7 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
try {
info.field.set(null, info.value);
} catch (IllegalAccessException e) {
LibJf.LOGGER.error("Could not write value", e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not write value", e);
}
}
syncFromClass();
@ -172,7 +173,7 @@ public abstract class ConfigInstanceAbstract implements ConfigInstance {
if (info.value == null) info.value = info.defaultValue;
info.tempValue = info.value == null ? null : info.value.toString();
} catch (IllegalAccessException e) {
LibJf.LOGGER.error("Could not read value", e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not read value", e);
}
}
for (ConfigInstance instance : subcategories.values()) {

View File

@ -1,9 +1,10 @@
package io.gitlab.jfronny.libjf.config.impl;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.gson.JsonElement;
import io.gitlab.jfronny.gson.JsonParser;
import io.gitlab.jfronny.libjf.unsafe.JfLanguageAdapter;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.impl.util.log.Log;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@ -27,10 +28,10 @@ public class ConfigInstanceRoot extends ConfigInstanceAbstract {
try (BufferedReader br = Files.newBufferedReader(path)) {
JsonElement element = JsonParser.parseReader(br);
if (element.isJsonObject()) loadObject(element.getAsJsonObject());
else LibJf.LOGGER.error("Invalid config: Not a JSON object for " + modId);
else Log.error(JfLanguageAdapter.LOG_CATEGORY, "Invalid config: Not a JSON object for " + modId);
}
catch (Exception e) {
LibJf.LOGGER.error("Could not read config for " + modId, e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not read config for " + modId, e);
}
}
syncFromClass();
@ -41,9 +42,9 @@ public class ConfigInstanceRoot extends ConfigInstanceAbstract {
public void write() {
JfConfigWatchService.lock(path, () -> {
try (BufferedWriter bw = Files.newBufferedWriter(path)) {
LibJf.GSON.toJson(writeObject(), bw);
ConfigHolderImpl.GSON.toJson(writeObject(), bw);
} catch (Exception e) {
LibJf.LOGGER.error("Could not write config", e);
Log.error(JfLanguageAdapter.LOG_CATEGORY, "Could not write config", e);
}
});
}

View File

@ -3,7 +3,7 @@ package io.gitlab.jfronny.libjf.config.impl;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.api.ConfigHolder;
import io.gitlab.jfronny.libjf.coprocess.ThreadCoProcess;
import io.gitlab.jfronny.libjf.interfaces.ThrowingRunnable;
import io.gitlab.jfronny.libjf.generic.ThrowingRunnable;
import net.fabricmc.loader.api.FabricLoader;
import java.io.Closeable;

View File

@ -1,12 +1,13 @@
package io.gitlab.jfronny.libjf.config.impl.entrypoint;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.api.ConfigHolder;
import io.gitlab.jfronny.libjf.config.api.JfConfig;
import io.gitlab.jfronny.libjf.config.impl.ConfigHolderImpl;
import io.gitlab.jfronny.libjf.unsafe.JfLanguageAdapter;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.entrypoint.EntrypointContainer;
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
import net.fabricmc.loader.impl.util.log.Log;
public class JfConfigSafe implements PreLaunchEntrypoint {
@Override
@ -18,7 +19,7 @@ public class JfConfigSafe implements PreLaunchEntrypoint {
public static void registerIfMissing(String modId, Class<?> klazz) {
if (!ConfigHolder.getInstance().isRegistered(modId)) {
LibJf.LOGGER.info("Registering config for " + modId);
Log.info(JfLanguageAdapter.LOG_CATEGORY, "Registering config for " + modId);
ConfigHolder.getInstance().register(modId, klazz);
}
}

View File

@ -1,10 +1,11 @@
package io.gitlab.jfronny.libjf.config.impl.entrypoint;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.config.api.JfConfig;
import io.gitlab.jfronny.libjf.config.impl.ConfigHolderImpl;
import io.gitlab.jfronny.libjf.unsafe.DynamicEntry;
import io.gitlab.jfronny.libjf.unsafe.JfLanguageAdapter;
import io.gitlab.jfronny.libjf.unsafe.UltraEarlyInit;
import net.fabricmc.loader.impl.util.log.Log;
public class JfConfigUnsafe implements UltraEarlyInit {
@Override
@ -12,6 +13,6 @@ public class JfConfigUnsafe implements UltraEarlyInit {
DynamicEntry.execute(ConfigHolderImpl.MODULE_ID, JfConfig.class,
s -> JfConfigSafe.registerIfMissing(s.modId(), s.instance().getClass())
);
LibJf.LOGGER.info("Finished LibJF config entrypoint");
Log.info(JfLanguageAdapter.LOG_CATEGORY, "Finished LibJF config entrypoint");
}
}

View File

@ -2,9 +2,9 @@ package io.gitlab.jfronny.libjf.data.manipulation.api;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.data.manipulation.impl.ResourcePackHook;
import io.gitlab.jfronny.libjf.interfaces.LazySupplier;
import io.gitlab.jfronny.libjf.interfaces.ThrowingRunnable;
import io.gitlab.jfronny.libjf.interfaces.ThrowingSupplier;
import io.gitlab.jfronny.libjf.generic.LazySupplier;
import io.gitlab.jfronny.libjf.generic.ThrowingRunnable;
import io.gitlab.jfronny.libjf.generic.ThrowingSupplier;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.resource.ResourcePack;

View File

@ -2,7 +2,7 @@ package io.gitlab.jfronny.libjf.data.manipulation.impl;
import io.gitlab.jfronny.libjf.ResourcePath;
import io.gitlab.jfronny.libjf.data.manipulation.api.UserResourceEvents;
import io.gitlab.jfronny.libjf.interfaces.LazySupplier;
import io.gitlab.jfronny.libjf.generic.LazySupplier;
import net.minecraft.resource.ResourcePack;
import net.minecraft.resource.ResourceType;
import net.minecraft.util.Identifier;

View File

@ -1,19 +1,30 @@
package io.gitlab.jfronny.libjf.unsafe;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.Flags;
import io.gitlab.jfronny.libjf.unsafe.inject.FabricLauncherClassUnlocker;
import io.gitlab.jfronny.libjf.unsafe.inject.KnotClassLoaderInterfaceAccessor;
import net.fabricmc.loader.api.LanguageAdapter;
import net.fabricmc.loader.impl.FabricLoaderImpl;
import net.fabricmc.loader.impl.util.log.Log;
import net.fabricmc.loader.impl.util.log.LogCategory;
import java.util.Set;
import java.util.stream.Collectors;
public class JfLanguageAdapter implements LanguageAdapter {
@Override
public native <T> T create(net.fabricmc.loader.api.ModContainer mod, String value, Class<T> type);
public static LogCategory LOG_CATEGORY = new LogCategory("libjf");
static {
FabricLoaderImpl.INSTANCE.getGameProvider().unlockClassPath(new FabricLauncherClassUnlocker(new KnotClassLoaderInterfaceAccessor(Thread.currentThread().getContextClassLoader())));
DynamicEntry.execute(LibJf.MOD_ID + ":preEarly", UltraEarlyInit.class, s -> s.instance().init());
DynamicEntry.execute(LibJf.MOD_ID + ":early", UltraEarlyInit.class, s -> s.instance().init());
LibJf.LOGGER.info("LibJF unsafe init completed");
Set<Flags.BooleanFlag> flags = Flags.getBoolFlags("unsafe.unlock");
if (flags.stream().map(Flags.BooleanFlag::value).reduce(false, (left, right) -> left || right)) {
Log.warn(LOG_CATEGORY, "Unlocking classpath due to: " + flags.stream().map(Flags.BooleanFlag::source).collect(Collectors.joining(", ")));
FabricLoaderImpl.INSTANCE.getGameProvider().unlockClassPath(new FabricLauncherClassUnlocker(new KnotClassLoaderInterfaceAccessor(Thread.currentThread().getContextClassLoader())));
}
DynamicEntry.execute("libjf:preEarly", UltraEarlyInit.class, s -> s.instance().init());
DynamicEntry.execute("libjf:early", UltraEarlyInit.class, s -> s.instance().init());
Log.info(LOG_CATEGORY, "LibJF unsafe init completed");
}
}

View File

@ -17,7 +17,7 @@ import java.util.jar.Manifest;
public record FabricLauncherClassUnlocker(KnotClassLoaderInterfaceAccessor classLoader) implements FabricLauncher {
static {
System.err.println("[libjf-unsafe-v0] Preparing to unlock classpath via reflection");
System.err.println("[libjf-unsafe-v0] Preparing to unlock classpath via reflection. This might cause issues");
}
@Override