[unsafe] Fix and remove unsafe.unlock

This commit is contained in:
Johannes Frohnmeyer 2022-08-22 00:12:19 +02:00
parent 1ce7ddaf38
commit 6e359462d2
Signed by: Johannes
GPG Key ID: E76429612C2929F4
23 changed files with 53 additions and 234 deletions

View File

@ -21,8 +21,8 @@ allprojects {
}
dependencies {
testmodRuntimeOnly("com.terraformersmc:modmenu:4.0.5")
testmodRuntimeOnly("net.fabricmc.fabric-api:fabric-api:$project.fabric_version")
modLocalRuntime("com.terraformersmc:modmenu:4.0.5")
modLocalRuntime(fabricApi.module("fabric-command-api-v2", "$project.fabric_version"))
compileOnly("io.gitlab.jfronny:commons:$rootProject.commons_version")
compileOnly("io.gitlab.jfronny:commons-gson:$rootProject.commons_version")
}

View File

@ -1,7 +1,7 @@
archivesBaseName = "libjf-config-reflect-v0"
dependencies {
api project(":libjf-base")
api project(":libjf-unsafe-v0")
api project(":libjf-config-v1")
api project(path: ":libjf-base", configuration: "dev")
api project(path: ":libjf-unsafe-v0", configuration: "dev")
api project(path: ":libjf-config-v1", configuration: "dev")
}

View File

@ -1,6 +1,5 @@
package io.gitlab.jfronny.libjf.config.impl.reflect.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;
@ -19,7 +18,6 @@ public class JfConfigReflectSafe implements PreLaunchEntrypoint {
public static void registerIfMissing(String modId, Class<? extends JfConfig> klazz) {
if (!ConfigHolder.getInstance().isRegistered(modId)) {
LibJf.LOGGER.info("Registering config for " + modId);
ConfigProvider.register(modId, klazz);
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.libjf.config.test;
package io.gitlab.jfronny.libjf.config.test.reflect;
import io.gitlab.jfronny.commons.serialize.gson.api.Ignore;
import io.gitlab.jfronny.libjf.config.api.*;

View File

@ -1,13 +1,13 @@
{
"libjf-config-v1-testmod.jfconfig.title": "JfConfig example",
"libjf-config-v1-testmod.jfconfig.disablePacks": "Disable resource packs",
"libjf-config-v1-testmod.jfconfig.intTest": "Int Test",
"libjf-config-v1-testmod.jfconfig.decimalTest": "Decimal Test",
"libjf-config-v1-testmod.jfconfig.dieStr": "String Test",
"libjf-config-v1-testmod.jfconfig.gsonOnlyStr.tooltip": "George",
"libjf-config-v1-testmod.jfconfig.enumTest": "Enum Test",
"libjf-config-v1-testmod.jfconfig.enumTest.tooltip": "Enum Test Tooltip",
"libjf-config-v1-testmod.jfconfig.enum.Test.Test": "Test",
"libjf-config-v1-testmod.jfconfig.enum.Test.ER": "ER",
"libjf-config-v1-testmod.jfconfig.moskau": "Moskau"
"libjf-config-reflect-v0-testmod.jfconfig.title": "JfConfig example",
"libjf-config-reflect-v0-testmod.jfconfig.disablePacks": "Disable resource packs",
"libjf-config-reflect-v0-testmod.jfconfig.intTest": "Int Test",
"libjf-config-reflect-v0-testmod.jfconfig.decimalTest": "Decimal Test",
"libjf-config-reflect-v0-testmod.jfconfig.dieStr": "String Test",
"libjf-config-reflect-v0-testmod.jfconfig.gsonOnlyStr.tooltip": "George",
"libjf-config-reflect-v0-testmod.jfconfig.enumTest": "Enum Test",
"libjf-config-reflect-v0-testmod.jfconfig.enumTest.tooltip": "Enum Test Tooltip",
"libjf-config-reflect-v0-testmod.jfconfig.enum.Test.Test": "Test",
"libjf-config-reflect-v0-testmod.jfconfig.enum.Test.ER": "ER",
"libjf-config-reflect-v0-testmod.jfconfig.moskau": "Moskau"
}

View File

@ -5,7 +5,7 @@
"environment": "*",
"entrypoints": {
"libjf:config": [
"io.gitlab.jfronny.libjf.config.test.TestConfig"
"io.gitlab.jfronny.libjf.config.test.reflect.TestConfig"
]
},
"custom": {

View File

@ -1,7 +1,7 @@
archivesBaseName = "libjf-config-v1"
dependencies {
api project(":libjf-base")
api project(path: ":libjf-base", configuration: "dev")
include fabricApi.module("fabric-resource-loader-v0", "${project.fabric_version}")
include modImplementation(fabricApi.module("fabric-command-api-v2", "${project.fabric_version}"))
modCompileOnly("com.terraformersmc:modmenu:4.0.5")

View File

@ -25,6 +25,7 @@ public class ConfigHolderImpl implements ConfigHolder {
if (isRegistered(modId)) {
LibJf.LOGGER.warn("Overriding config class of " + modId + " to " + config);
}
LibJf.LOGGER.info("Registering config for " + modId);
configs.put(modId, config);
config.getFilePath().ifPresent(path -> configsByPath.put(path, config));
}

View File

@ -71,7 +71,7 @@ public class CategoryBuilderImpl<Builder extends CategoryBuilderImpl<Builder>> i
@Override
public Builder category(String id, CategoryBuilderFunction builder) {
checkBuilt();
categories.add(builder.apply(new CategoryBuilderImpl(id, categoryPath + id + ".")));
categories.add(builder.apply(new CategoryBuilderImpl(id, categoryPath + id + ".").setTranslationPrefix(translationPrefix + id + ".")));
return asBuilder();
}

View File

@ -18,7 +18,7 @@ public class TestConfigCustom {
.referenceConfig("libjf-config-reflect-v0-testmod")
.value("someValue", 10, -50, 50, () -> someValue, v -> someValue = v)
.value("someOther", "Yes", () -> someOther, v -> someOther = v)
.category("SomeCategory", builder1 -> builder1
.category("someCategory", builder1 -> builder1
.value("someBool", true, () -> SomeCategory.someBool, v -> SomeCategory.someBool = v)
)
);

View File

@ -1,7 +1,7 @@
archivesBaseName = "libjf-data-manipulation-v0"
dependencies {
api project(":libjf-base")
api project(":libjf-unsafe-v0")
api project(path: ":libjf-base", configuration: "dev")
api project(path: ":libjf-unsafe-v0", configuration: "dev")
modApi(fabricApi.module("fabric-api-base", "$rootProject.fabric_version"))
}

View File

@ -1,6 +1,6 @@
archivesBaseName = "libjf-data-v0"
dependencies {
api project(":libjf-base")
api project(path: ":libjf-base", configuration: "dev")
include fabricApi.module("fabric-resource-loader-v0", "${project.fabric_version}")
}

View File

@ -1,5 +1,5 @@
archivesBaseName = "libjf-devutil-v0"
dependencies {
api project(":libjf-base")
api project(path: ":libjf-base", configuration: "dev")
}

View File

@ -1,19 +1,31 @@
package io.gitlab.jfronny.libjf.devutil.mixin;
import com.mojang.authlib.minecraft.UserApiService;
import net.minecraft.client.util.ProfileKeys;
import net.minecraft.network.encryption.PlayerKeyPair;
import net.minecraft.network.encryption.PlayerPublicKey;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.Overwrite;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Mixin(ProfileKeys.class)
public class ProfileKeysMixin {
@Redirect(method = "<init>(Lcom/mojang/authlib/minecraft/UserApiService;Ljava/util/UUID;Ljava/nio/file/Path;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/ProfileKeys;getKeyPair(Lcom/mojang/authlib/minecraft/UserApiService;)Ljava/util/concurrent/CompletableFuture;"))
private CompletableFuture<Optional<PlayerKeyPair>> libjf$redirectGetKeyPair(ProfileKeys instance, UserApiService userApiService) {
/**
* @author JFronny
* @reason Do not load keys!
*/
@Overwrite
public CompletableFuture<Optional<PlayerPublicKey.PublicKeyData>> refresh() {
return CompletableFuture.completedFuture(Optional.empty());
}
/**
* @author JFronny
* @reason Do not load keys!
*/
@Overwrite
private CompletableFuture<Optional<Object>> getKeyPair(Optional<PlayerKeyPair> currentKey) {
return CompletableFuture.completedFuture(Optional.empty());
}
}

View File

@ -1,6 +1,6 @@
archivesBaseName = "libjf-translate-v1"
dependencies {
api project(":libjf-base")
api project(":libjf-config-v1")
api project(path: ":libjf-base", configuration: "dev")
api project(path: ":libjf-config-v1", configuration: "dev")
}

View File

@ -1,5 +1,5 @@
archivesBaseName = "libjf-unsafe-v0"
dependencies {
api project(":libjf-base")
api project(path: ":libjf-base", configuration: "dev")
}

View File

@ -2,7 +2,7 @@ package io.gitlab.jfronny.libjf.unsafe;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import net.fabricmc.loader.api.metadata.ModMetadata;
import net.fabricmc.loader.impl.ModContainerImpl;
import net.fabricmc.loader.impl.metadata.EntrypointMetadata;
import java.lang.reflect.InvocationTargetException;
@ -46,11 +46,11 @@ public class DynamicEntry {
private static Collection<EntrypointContainer> getEntrypointTargets(final String entrypoint) {
final List<EntrypointContainer> entrypoints = new LinkedList<>();
for (final ModContainer mod : FabricLoader.getInstance().getAllMods()) {
final List<Object> modEntrypoints = getEntrypoints(mod.getMetadata(), entrypoint);
final List<EntrypointMetadata> modEntrypoints = ((ModContainerImpl)mod).getInfo().getEntrypoints(entrypoint);
if (modEntrypoints != null) {
for (final Object metadata : modEntrypoints) {
entrypoints.add(new EntrypointContainer(getValue(metadata), mod.getMetadata().getId()));
for (final EntrypointMetadata metadata : modEntrypoints) {
entrypoints.add(new EntrypointContainer(metadata.getValue(), mod.getMetadata().getId()));
}
}
}
@ -58,27 +58,6 @@ public class DynamicEntry {
return entrypoints;
}
@SuppressWarnings("unchecked")
private static List<Object> getEntrypoints(Object metadata, String name) {
try {
var method = metadata.getClass().getMethod("getEntrypoints", String.class);
method.setAccessible(true);
return (List<Object>) method.invoke(metadata, name);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private static String getValue(Object object) {
try {
var method = object.getClass().getMethod("getValue");
method.setAccessible(true);
return (String) method.invoke(object);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
record EntrypointContainer(String entrypoint, String mod) {
}

View File

@ -2,16 +2,9 @@ package io.gitlab.jfronny.libjf.unsafe;
import io.gitlab.jfronny.commons.log.Logger;
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
import io.gitlab.jfronny.libjf.Flags;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.gson.HiddenAnnotationExclusionStrategy;
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 java.util.Set;
import java.util.stream.Collectors;
public class JfLanguageAdapter implements LanguageAdapter {
@Override
@ -19,12 +12,6 @@ public class JfLanguageAdapter implements LanguageAdapter {
static {
Logger.registerFactory(FLLogger::new); // Reset in LibJf entrypoint
Set<Flags.BooleanFlag> flags = Flags.getBoolFlags("unsafe.unlock");
if (flags.stream().map(Flags.BooleanFlag::value).reduce(false, (left, right) -> left || right)) {
LibJf.LOGGER.warn("Unlocking classpath due to: " + flags.stream().map(Flags.BooleanFlag::source).collect(Collectors.joining(", ")));
FabricLoaderImpl.INSTANCE.getGameProvider().unlockClassPath(new FabricLauncherClassUnlocker(new KnotClassLoaderInterfaceAccessor(Thread.currentThread().getContextClassLoader())));
LibJf.LOGGER.warn("Completed classpath unlock");
}
HiddenAnnotationExclusionStrategy.register();
GsonHolder.register();
DynamicEntry.execute("libjf:preEarly", UltraEarlyInit.class, s -> s.instance().init());

View File

@ -1,96 +0,0 @@
package io.gitlab.jfronny.libjf.unsafe.inject;
import io.gitlab.jfronny.libjf.LibJf;
import io.gitlab.jfronny.libjf.unsafe.*;
import net.fabricmc.api.*;
import net.fabricmc.loader.impl.launch.*;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.jar.*;
public record FabricLauncherClassUnlocker(KnotClassLoaderInterfaceAccessor classLoader) implements FabricLauncher {
@Override
public MappingConfiguration getMappingConfiguration() {
return invalidCall();
}
@Override
public void addToClassPath(Path path, String... allowedPrefixes) {
LibJf.LOGGER.debug("Adding " + path + " to classpath.");
classLoader.getDelegate().setAllowedPrefixes(path, allowedPrefixes);
classLoader.getDelegate().addCodeSource(path);
}
@Override
public void setAllowedPrefixes(Path path, String... prefixes) {
classLoader.getDelegate().setAllowedPrefixes(path, prefixes);
}
@Override
public void setValidParentClassPath(Collection<Path> paths) {
invalidCall();
}
@Override
public EnvType getEnvironmentType() {
return invalidCall();
}
@Override
public boolean isClassLoaded(String name) {
return invalidCall();
}
@Override
public Class<?> loadIntoTarget(String name) throws ClassNotFoundException {
return invalidCall();
}
@Override
public InputStream getResourceAsStream(String name) {
return invalidCall();
}
@Override
public ClassLoader getTargetClassLoader() {
return invalidCall();
}
@Override
public byte[] getClassByteArray(String name, boolean runTransformers) throws IOException {
return invalidCall();
}
@Override
public Manifest getManifest(Path originPath) {
return invalidCall();
}
@Override
public boolean isDevelopment() {
return invalidCall();
}
@Override
public String getEntrypoint() {
return invalidCall();
}
@Override
public String getTargetNamespace() {
return invalidCall();
}
@Override
public List<Path> getClassPath() {
return invalidCall();
}
private <T> T invalidCall() {
LibJf.LOGGER.warn("Attempted invalid call in class path unlocker");
throw new IllegalStateException("unlockClassPath attempted to call a method not implemented here");
}
}

View File

@ -1,36 +0,0 @@
package io.gitlab.jfronny.libjf.unsafe.inject;
import java.lang.reflect.*;
import java.nio.file.*;
public record KnotClassDelegateAccessor(Object delegate) {
private static final Method addCodeSourceMethod;
private static final Method setAllowedPrefixesMethod;
static {
try {
Class<?> klazz = Class.forName("net.fabricmc.loader.impl.launch.knot.KnotClassDelegate");
addCodeSourceMethod = klazz.getDeclaredMethod("addCodeSource", Path.class);
addCodeSourceMethod.setAccessible(true);
setAllowedPrefixesMethod = klazz.getDeclaredMethod("setAllowedPrefixes", Path.class, String[].class);
setAllowedPrefixesMethod.setAccessible(true);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new IllegalStateException("Could not build accessor for class delegate. This version of fabric is likely not yet supported", e);
}
}
public void addCodeSource(Path url) {
try {
addCodeSourceMethod.invoke(delegate, url);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Could not invoke addURL on class loader. This version of fabric is likely not yet supported", e);
}
}
public void setAllowedPrefixes(Path url, String... prefixes) {
try {
setAllowedPrefixesMethod.invoke(delegate, url, prefixes);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Could not invoke setAllowedPrefixes on class delegate. This version of fabric is likely not yet supported", e);
}
}
}

View File

@ -1,25 +0,0 @@
package io.gitlab.jfronny.libjf.unsafe.inject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public record KnotClassLoaderInterfaceAccessor(ClassLoader loader) {
private static final Method getDelegateMethod;
static {
try {
Class<?> klazz = Class.forName("net.fabricmc.loader.impl.launch.knot.KnotClassLoader");
getDelegateMethod = klazz.getDeclaredMethod("getDelegate");
getDelegateMethod.setAccessible(true);
} catch (ClassNotFoundException | NoSuchMethodException e) {
throw new IllegalStateException("Could not build accessor for class loader. This version of fabric is likely not yet supported", e);
}
}
public KnotClassDelegateAccessor getDelegate() {
try {
return new KnotClassDelegateAccessor(getDelegateMethod.invoke(loader));
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Could not invoke getDelegate on class loader. This version of fabric is likely not yet supported", e);
}
}
}

View File

@ -14,8 +14,7 @@
"custom": {
"libjf": {
"asm.export": true,
"asm.log": true,
"unsafe.unlock": false
"asm.log": true
}
}
}

View File

@ -1,7 +1,7 @@
archivesBaseName = "libjf-web-v0"
dependencies {
api project(":libjf-base")
api project(":libjf-config-v1")
api project(path: ":libjf-base", configuration: "dev")
api project(path: ":libjf-config-v1", configuration: "dev")
include modImplementation(fabricApi.module("fabric-command-api-v2", "${rootProject.fabric_version}"))
}