Use reflection-based DeepCloner in FabricMetaApi.addFabric to allow caching VersionInfo

This commit is contained in:
Johannes Frohnmeyer 2022-02-06 15:17:15 +01:00
parent de8fcbb267
commit 0988aefbeb
Signed by: Johannes
GPG Key ID: E76429612C2929F4
7 changed files with 57 additions and 17 deletions

View File

@ -131,7 +131,7 @@ public class InstanceManageControls {
public VersionInfo getVersionInfo() throws IOException {
return VERSION_INFO_CACHE.get(Tuple.of(selected.id, fabric.get() ? selectedFabric.loader.version : ""), () -> {
VersionInfo vi = McApi.getVersionInfo(selected);
if (fabric.get()) FabricMetaApi.addFabric(vi, selectedFabric.loader.version, FabricMetaApi.FabricVersionInfoType.Both);
if (fabric.get()) vi = FabricMetaApi.addFabric(vi, selectedFabric.loader.version, FabricMetaApi.FabricVersionInfoType.Both);
return vi;
});
}

View File

@ -0,0 +1,37 @@
package io.gitlab.jfronny.inceptum.util;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
public class DeepCloner {
public static <T> T clone(T source) {
try {
return (T) cloneI(source);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
throw new RuntimeException("Could not clone object", e);
}
}
private static Object cloneI(Object source) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
if (source == null) return null;
if (source instanceof String
|| source instanceof Integer
|| source instanceof Byte
|| source instanceof Short
|| source instanceof Double
|| source instanceof Float)
return source;
if (source instanceof List<?> list) return List.copyOf(list);
if (source instanceof Map<?, ?> map) return Map.copyOf(map);
if (source instanceof Set<?> set) return new LinkedHashSet<>(set);
if (source instanceof Date date) return new Date(date.getTime());
Class<?> klazz = source.getClass();
if (!klazz.getName().startsWith("io.gitlab.jfronny.inceptum.model"))
throw new IllegalStateException("Default java classes must have special impls! (" + klazz.getName() + ")");
Object instance = klazz.getConstructor().newInstance();
for (Field field : klazz.getFields())
field.set(instance, cloneI(field.get(source)));
return instance;
}
}

View File

@ -63,18 +63,21 @@ public class InstanceLauncher {
VersionInfo versionInfo = McApi.getVersionInfo(versionDataSimple);
// Add fabric metadata if using fabric
if (instance.isFabric()) {
FabricMetaApi.addFabric(versionInfo, instance.getLoaderVersion(), launchType.fabricMetaType);
versionInfo = FabricMetaApi.addFabric(versionInfo, instance.getLoaderVersion(), launchType.fabricMetaType);
}
// Ensure libs/assets are present
DownloadLibrariesStep.execute(versionInfo, new AtomicBoolean(false), new ProcessState());
// Prepare arguments
List<String> args = new LinkedList<>();
// JVM path
args.add(Objects.requireNonNullElseGet(instance.java, () ->
JvmUtils.getJvmMain(MetaHolder.NATIVES_DIR
.resolve(versionInfo.javaVersion.component)
.resolve(Integer.toString(versionInfo.javaVersion.majorVersion)))
.toAbsolutePath().toString()));
{
final VersionInfo lambdaVersionInfo = versionInfo;
args.add(Objects.requireNonNullElseGet(instance.java, () ->
JvmUtils.getJvmMain(MetaHolder.NATIVES_DIR
.resolve(lambdaVersionInfo.javaVersion.component)
.resolve(Integer.toString(lambdaVersionInfo.javaVersion.majorVersion)))
.toAbsolutePath().toString()));
}
// Java classpath
StringBuilder classPath = new StringBuilder();
for (ArtifactInfo artifact : VersionInfoLibraryResolver.getRelevant(versionInfo)) {

View File

@ -6,6 +6,7 @@ import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.mojang.Rules;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionsListInfo;
import io.gitlab.jfronny.inceptum.util.DeepCloner;
import io.gitlab.jfronny.inceptum.util.Utils;
import java.io.IOException;
@ -30,13 +31,13 @@ public class FabricMetaApi {
return Utils.downloadObject(META_URL + "v2/versions/loader/" + gameVersion + "/" + fabricVersion, FabricVersionLoaderInfo.WithMeta.class);
}
//TODO don't mutate the object to allow cache, then re-enable cache in McApi
public static void addFabric(VersionInfo version, String fabricVersion, FabricVersionInfoType type) throws IOException {
public static VersionInfo addFabric(VersionInfo version, String fabricVersion, FabricVersionInfoType type) throws IOException {
VersionInfo result = DeepCloner.clone(version);
FabricVersionLoaderInfo ver = getLoaderVersion(version.id, fabricVersion);
if (!(ver instanceof FabricVersionLoaderInfo.WithMeta verWithMeta)) throw new IOException("Doesn't hold metadata");
FabricVersionLoaderInfo.WithMeta.LauncherMeta meta = verWithMeta.launcherMeta;
if (meta.version != 1) throw new IOException("Unsupported fabric launcherMeta version: " + meta.version);
version.mainClass = type == FabricVersionInfoType.Server ? meta.mainClass.server : meta.mainClass.client;
result.mainClass = type == FabricVersionInfoType.Server ? meta.mainClass.server : meta.mainClass.client;
List<VersionInfo.Library> libs = new ArrayList<>(version.libraries);
for (FabricVersionLoaderInfo.WithMeta.LauncherMeta.Libraries.Library library : meta.libraries.common)
libs.add(convertLib(library));
@ -54,8 +55,9 @@ public class FabricMetaApi {
libs.add(convertLib(floader));
floader.name = ver.intermediary.maven;
libs.add(convertLib(floader));
version.libraries = List.copyOf(libs);
version.id = InstanceMeta.floaderPrefix + fabricVersion + "-" + version.id;
result.libraries = List.copyOf(libs);
result.id = InstanceMeta.floaderPrefix + fabricVersion + "-" + version.id;
return result;
}
private static VersionInfo.Library convertLib(FabricVersionLoaderInfo.WithMeta.LauncherMeta.Libraries.Library library) {

View File

@ -24,7 +24,7 @@ public class McApi {
}
public static VersionInfo getVersionInfo(VersionsListInfo listInfo) throws IOException {
return downloadObject(listInfo.url, listInfo.sha1, VersionInfo.class, false);
return downloadObject(listInfo.url, listInfo.sha1, VersionInfo.class);
}
public static AssetIndex getAssetIndex(VersionInfo info) throws IOException, URISyntaxException {

View File

@ -41,7 +41,7 @@ public class Steps {
if (version.id.equals(im.getMinecraftVersion())) {
found = true;
VersionInfo vi = McApi.getVersionInfo(version);
if (im.isFabric()) FabricMetaApi.addFabric(vi, im.getLoaderVersion(), FabricMetaApi.FabricVersionInfoType.Both);
if (im.isFabric()) vi = FabricMetaApi.addFabric(vi, im.getLoaderVersion(), FabricMetaApi.FabricVersionInfoType.Both);
LoaderInfo li = im.isFabric()
? new LoaderInfo(LoaderInfo.Type.Fabric, im.getLoaderVersion())
: LoaderInfo.NONE;

View File

@ -72,9 +72,7 @@ public class Utils {
private static <T> T downloadObject(String url, ThrowingSupplier<String, Exception> sourceString, Type type, boolean cache) throws IOException {
try {
ThrowingSupplier<T, Exception> builder = () -> GsonHolder.getGson().fromJson(sourceString.get(), type);
if (cache)
return OBJECT_CACHE.get(HashUtils.sha1(url.getBytes(StandardCharsets.UTF_8)), builder, type);
return builder.get();
return cache ? OBJECT_CACHE.get(HashUtils.sha1(url.getBytes(StandardCharsets.UTF_8)), builder, type) : builder.get();
} catch (Exception e) {
throw new IOException("Could not download object and no cache exists", e);
}