Basic instance editing, 1.8.9 support

This commit is contained in:
JFronny 2021-10-30 16:12:39 +02:00
parent ea2b2e5452
commit 2adf5cac1b
No known key found for this signature in database
GPG Key ID: BEC5ACBBD4EE17E5
15 changed files with 389 additions and 140 deletions

View File

@ -59,6 +59,7 @@ public class Inceptum {
public static final Path INSTANCE_DIR = Path.of("run/instances");
public static final Path ASSETS_DIR = Path.of("run/assets");
public static final Path LIBRARIES_DIR = Path.of("run/libraries");
public static final Path NATIVES_DIR = Path.of("run/natives");
private static final Path CONFIG_PATH = Path.of("run/glaunch2.json");
public static final Path ACCOUNTS_PATH = Path.of("run/accounts.json");
public static InceptumVersion VERSION;
@ -123,7 +124,8 @@ public class Inceptum {
protected static void dispose() {
imGuiGl3.dispose();
imGuiGlfw.dispose();
ImGui.destroyContext();
//TODO figure out why this is a problem
//ImGui.destroyContext();
Callbacks.glfwFreeCallbacks(handle);
GLFW.glfwDestroyWindow(handle);
GLFW.glfwTerminate();

View File

@ -3,6 +3,7 @@ package io.gitlab.jfronny.inceptum.install.steps;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import io.gitlab.jfronny.inceptum.util.Utils;
@ -16,7 +17,7 @@ public class DownloadClientStep implements Step {
public void execute(SetupStepInfo info, AtomicBoolean stopThread) throws IOException {
Path path = Inceptum.LIBRARIES_DIR.resolve("net/minecraft/minecraft");
if (!Files.exists(path)) Files.createDirectories(path);
path = path.resolve(info.version().id + ".jar");
path = path.resolve(InstanceMeta.getMinecraftVersion(info.version().id) + ".jar");
if (Files.exists(path)) return;
VersionInfo.Downloads.Download client = info.version().downloads.client;
Inceptum.LOGGER.info("Downloading client");

View File

@ -3,30 +3,47 @@ package io.gitlab.jfronny.inceptum.install.steps;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.ArtifactInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.VersionInfoLibraryResolver;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
public class DownloadLibrariesStep implements Step {
@Override
public void execute(SetupStepInfo info, AtomicBoolean stopThread) throws IOException {
for (VersionInfo.Library.Downloads.Artifact artifact : VersionInfoLibraryResolver.getRelevant(info.version())) {
for (ArtifactInfo artifact : VersionInfoLibraryResolver.getRelevant(info.version())) {
if (stopThread.get()) return;
Path path = Inceptum.LIBRARIES_DIR.resolve(artifact.path);
if (Files.exists(path)) continue;
//TODO allow maven-like download for fabric
Inceptum.LOGGER.info("Downloading library: " + artifact.path);
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
if (!artifact.url.endsWith(".jar")) {
Inceptum.LOGGER.info("Not a valid URL for a jar: " + artifact.url);
continue;
if (!Files.exists(path)) {
Inceptum.LOGGER.info("Downloading library: " + artifact.path);
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
if (!artifact.url.endsWith(".jar")) {
Inceptum.LOGGER.info("Not a valid URL for a jar: " + artifact.url);
continue;
}
Utils.downloadFile(artifact.url, artifact.sha1, path);
}
if (artifact.isNative) {
Inceptum.LOGGER.info("Extracting natives");
try (FileSystem libFs = FileSystems.newFileSystem(new URI("jar", path.toUri().toString(), null), new HashMap<>())) {
for (Path path1 : Files.list(libFs.getPath(".")).toList()) {
Utils.copyRecursive(path1, Inceptum.NATIVES_DIR.resolve(InstanceMeta.getMinecraftVersion(info.version().id)));
}
}
catch (Throwable t) {
Files.delete(path);
throw new IOException("Could not extract native", t);
}
}
Utils.downloadFile(artifact.url, artifact.sha1, path);
}
}
}

View File

@ -3,6 +3,7 @@ package io.gitlab.jfronny.inceptum.install.steps;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.LoaderInfo;
import java.io.IOException;
@ -24,5 +25,6 @@ public class SetupDirsStep implements Step {
Files.createDirectories(iDir.resolve("saves"));
Files.createDirectories(iDir.resolve("screenshots"));
}
Files.createDirectories(Inceptum.NATIVES_DIR.resolve(InstanceMeta.getMinecraftVersion(info.version().id)));
}
}

View File

@ -15,10 +15,11 @@ public class WriteMetadataStep implements Step {
@Override
public void execute(SetupStepInfo info, AtomicBoolean stopThread) throws IOException {
Inceptum.LOGGER.info("Writing metadata");
Path metaDir = Inceptum.INSTANCE_DIR.resolve(info.name()).resolve("inceptum.lock");
Path metaDir = Inceptum.INSTANCE_DIR.resolve(info.name()).resolve("instance.json");
InstanceMeta meta = new InstanceMeta();
meta.version = info.version().id;
Utils.writeObject(metaDir, meta);
Files.delete(Inceptum.INSTANCE_DIR.resolve(info.name()).resolve("SETUP"));
Path lock = Inceptum.INSTANCE_DIR.resolve(info.name()).resolve("inceptum.setup.lock");
if (Files.exists(lock)) Files.delete(lock);
}
}

View File

@ -0,0 +1,19 @@
package io.gitlab.jfronny.inceptum.model.inceptum;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
public class ArtifactInfo {
public final String path;
public final String sha1;
public final int size;
public final String url;
public final boolean isNative;
public ArtifactInfo(VersionInfo.Library.Downloads.Artifact artifact, boolean isNative) {
path = artifact.path;
sha1 = artifact.sha1;
size = artifact.size;
url = artifact.url;
this.isNative = isNative;
}
}

View File

@ -1,18 +1,42 @@
package io.gitlab.jfronny.inceptum.model.inceptum;
import io.gitlab.jfronny.inceptum.gson.GsonIgnore;
import java.nio.file.Files;
import java.nio.file.Path;
public class InstanceMeta {
private static final String floaderPrefix = "fabric-loader-";
@GsonIgnore public static final String floaderPrefix = "fabric-loader-";
public String version;
public String java; //TODO allow configuring
public Long minMem;
public Long maxMem;
public boolean isFabric() {
return version.startsWith(floaderPrefix);
}
public String getMinecraftVersion() {
return isFabric() ? version.substring(version.lastIndexOf('-') + 1) : version;
return getMinecraftVersion(version);
}
public static String getMinecraftVersion(String id) {
return id.startsWith(floaderPrefix) ? id.substring(id.lastIndexOf('-') + 1) : id;
}
public String getLoaderVersion() {
return isFabric() ? version.substring(floaderPrefix.length()).split("-")[0] : "";
}
public String getJava() {
if (java == null) {
//TODO allow manually selecting a default JVM, MultiMC autodetect
Path f = Path.of(System.getProperty("java.home")).resolve("bin");
Path t = f.resolve("java");
if (!Files.exists(t)) t = f.resolve("javaw");
if (!Files.exists(t)) t = f.resolve("java.exe");
if (!Files.exists(t)) t = f.resolve("javaw.exe");
return t.toAbsolutePath().toString();
} else return java;
}
}

View File

@ -12,6 +12,7 @@ public class VersionInfo extends VersionsListInfo {
public JavaVersion javaVersion;
public List<Library> libraries;
public String mainClass;
public String minecraftArguments;
public Integer minimumLauncherVersion;
public static class Arguments {

View File

@ -11,6 +11,7 @@ import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Formatter;
import java.util.Locale;
import java.util.function.Function;
@ -129,6 +130,41 @@ public class Utils {
});
}
public static void copyRecursive(Path source, Path destination) throws IOException {
copyRecursive(source, destination, StandardCopyOption.COPY_ATTRIBUTES);
}
public static void copyRecursive(Path source, Path destination, CopyOption... copyOptions) throws IOException {
if (!Files.exists(destination)) Files.createDirectories(destination);
if(Files.isDirectory(source)) {
/*Files.walk(source)
.forEach(sourcePath -> {
try {
Path destinationPath = destination.resolve(source.getFileName().toString());
Path targetPath = destinationPath.resolve(source.relativize(sourcePath).toString());
Files.copy(sourcePath, targetPath, copyOptions);
} catch (IOException e) {
Inceptum.LOGGER.error("Could not recursively copy", e);
}
});*/
Files.list(source).forEach(sourcePath -> {
try {
copyRecursive(sourcePath, destination.resolve(sourcePath.getFileName().toString()), copyOptions);
} catch (IOException e) {
Inceptum.LOGGER.error("Could not recursively copy", e);
}
});
} else if(Files.exists(source)) {
Path target = destination.resolve(source.getFileName().toString());
if (!Files.exists(target)
|| Arrays.asList(copyOptions).contains(StandardCopyOption.REPLACE_EXISTING))
Files.copy(source, target, copyOptions);
} else {
throw new FileNotFoundException(source.toAbsolutePath().toString());
}
}
public static void openWebBrowser(URI uri) {
try {
if (OS.equals("linux") && Utils.executableInPath("xdg-open")) {

View File

@ -1,24 +1,25 @@
package io.gitlab.jfronny.inceptum.util;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.model.inceptum.ArtifactInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import java.util.LinkedHashSet;
import java.util.Set;
public class VersionInfoLibraryResolver {
public static Set<VersionInfo.Library.Downloads.Artifact> getRelevant(VersionInfo version) {
Set<VersionInfo.Library.Downloads.Artifact> artifacts = new LinkedHashSet<>();
public static Set<ArtifactInfo> getRelevant(VersionInfo version) {
Set<ArtifactInfo> artifacts = new LinkedHashSet<>();
for (VersionInfo.Library library : version.libraries) {
if (library.rules != null && !library.rules.allow()) continue;
if (library.downloads.classifiers != null && library.natives != null && library.natives.containsKey(Utils.OS)) {
artifacts.add(library.downloads.classifiers.get(library.natives.get(Utils.OS)));
artifacts.add(new ArtifactInfo(library.downloads.classifiers.get(library.natives.get(Utils.OS)), true));
}
if (library.downloads.artifact == null) {
Inceptum.LOGGER.info("Null library artifact @ " + library.name);
continue;
}
artifacts.add(library.downloads.artifact);
artifacts.add(new ArtifactInfo(library.downloads.artifact, false));
}
return artifacts;
}

View File

@ -2,6 +2,7 @@ package io.gitlab.jfronny.inceptum.util.api;
import com.google.gson.reflect.TypeToken;
import io.gitlab.jfronny.inceptum.model.fabric.FabricVersionLoaderInfo;
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;
@ -45,7 +46,7 @@ public class FabricMetaApi {
floader.url = "https://maven.fabricmc.net/";
libs.add(convertLib(floader));
version.libraries = List.copyOf(libs);
version.id = "fabric-loader-" + fabricVersion + "-" + version.id;
version.id = InstanceMeta.floaderPrefix + fabricVersion + "-" + version.id;
}
private static VersionInfo.Library convertLib(FabricVersionLoaderInfo.WithMeta.LauncherMeta.Libraries.Library library) {

View File

@ -0,0 +1,62 @@
package io.gitlab.jfronny.inceptum.windows;
import imgui.ImGui;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.Utils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
//TODO allow changing name (moving), changing version, managing mods etc
public class InstanceEditWindow extends Window {
private final Path path;
private final InstanceMeta instance;
private final ImString name;
public InstanceEditWindow(Path path, InstanceMeta instance) {
super("Edit " + path.getFileName().toString());
this.path = path;
this.instance = instance;
name = new ImString(path.getFileName().toString(), NewInstanceWindow.MAX_NAME_LENGTH);
}
@Override
public void draw() {
if (ImGui.beginTabBar("InstanceEdit" + path)) {
if (ImGui.beginTabItem("General")) {
ImGui.inputTextWithHint("Name", "Name of this instance", name);
if (!Utils.VALID_FILENAME.matcher(name.get()).matches())
ImGui.text("Invalid name");
else if (!Files.exists(Inceptum.INSTANCE_DIR.resolve(name.get())) && ImGui.button("Rename")) {
try {
Path newPath = Inceptum.INSTANCE_DIR.resolve(name.get());
Files.move(path, newPath);
close();
Inceptum.open(new InstanceEditWindow(newPath, instance));
} catch (IOException e) {
e.printStackTrace();
}
}
if (ImGui.button("Delete")) Inceptum.open(new AlertWindow("Are you sure?", "This instance will be removed forever (a long time)", () -> {
close();
try {
Utils.deleteRecursive(path);
} catch (IOException e) {
Inceptum.LOGGER.error("Could not delete the instance", e);
Inceptum.open(new AlertWindow("Could not delete", e.toString()));
}
}, () -> {}));
ImGui.endTabItem();
}
if (instance.isFabric() && ImGui.beginTabItem("Mods")) {
ImGui.text("Mod editing is not currently implemented");
ImGui.text("Please be patient");
ImGui.endTabItem();
}
ImGui.endTabBar();
}
}
}

View File

@ -1,30 +1,31 @@
package io.gitlab.jfronny.inceptum.windows;
import imgui.ImGui;
import imgui.flag.ImGuiTableFlags;
import imgui.flag.ImGuiWindowFlags;
import imgui.type.ImBoolean;
import imgui.type.ImInt;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.install.Steps;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.mojang.MinecraftArgument;
import io.gitlab.jfronny.inceptum.model.inceptum.LoaderInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionsListInfo;
import io.gitlab.jfronny.inceptum.util.MapAppender;
import io.gitlab.jfronny.inceptum.util.ProcessUtils;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.VersionInfoLibraryResolver;
import io.gitlab.jfronny.inceptum.util.api.FabricMetaApi;
import io.gitlab.jfronny.inceptum.util.api.McApi;
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.util.api.account.AuthInfo;
import io.gitlab.jfronny.inceptum.util.api.account.MicrosoftAccount;
import io.gitlab.jfronny.inceptum.windows.control.InstanceView;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
public class MainWindow extends Window {
private final ImBoolean darkTheme = new ImBoolean(Inceptum.CONFIG.darkTheme);
@ -44,6 +45,36 @@ public class MainWindow extends Window {
ImGui.beginMenuBar();
if (ImGui.beginMenu("File")) {
if (ImGui.menuItem("New Instance")) Inceptum.open(new NewInstanceWindow());
if (ImGui.menuItem("Re-download resources")) {
try {
Files.list(Inceptum.INSTANCE_DIR).forEach(p -> {
try {
if (Files.exists(p.resolve("inceptum.setup.lock"))) return;
if (Files.exists(p.resolve("inceptum.lock"))) return;
InstanceMeta im = Utils.loadObject(p.resolve("instance.json"), InstanceMeta.class);
for (VersionsListInfo version : McApi.getVersions().versions) {
if (version.id.equals(im.getMinecraftVersion())) {
VersionInfo vi = McApi.getVersionInfo(version);
if (im.isFabric()) FabricMetaApi.addFabric(vi, im.getLoaderVersion());
LoaderInfo li = im.isFabric()
? new LoaderInfo(LoaderInfo.Type.Fabric, im.getLoaderVersion())
: LoaderInfo.NONE;
SetupStepInfo info = new SetupStepInfo(vi, li, p.getFileName().toString());
for (Step step : Steps.STEPS) {
step.execute(info, new AtomicBoolean(false));
}
}
}
} catch (IOException e) {
Inceptum.LOGGER.error("Could not execute refresh task", e);
Inceptum.open(new AlertWindow("Something went wrong", e.toString()));
}
});
} catch (IOException e) {
Inceptum.LOGGER.error("Could not execute refresh task", e);
Inceptum.open(new AlertWindow("Something went wrong", e.toString()));
}
}
if (ImGui.menuItem("Exit Inceptum")) Inceptum.exit();
ImGui.endMenu();
}
@ -93,109 +124,6 @@ public class MainWindow extends Window {
ImGui.text("You have not yet created an instance");
ImGui.text("Use File->New Instance to do so");
}
else if (ImGui.beginTable("Instances", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
for (Path path : paths) {
if (Files.exists(path.resolve("inceptum.setup.lock"))) {
ImGui.tableNextColumn();
ImGui.text("Setting up");
ImGui.tableNextColumn();
ImGui.text("This instance is currently being set up");
continue;
}
if (!Files.exists(path.resolve("instance.json"))) {
Inceptum.LOGGER.error("Invalid instance (doesn't contain instance.json): " + path);
continue;
}
InstanceMeta instance;
try {
instance = Utils.loadObject(path.resolve("instance.json"), InstanceMeta.class);
} catch (IOException e) {
Inceptum.LOGGER.error("Could not load instance.json", e);
continue;
}
ImGui.tableNextColumn();
boolean disabled = false;
if (Files.exists(path.resolve("inceptum.lock"))) {
try {
if (ProcessUtils.isProcessAlive(Files.readString(path.resolve("inceptum.lock"))))
disabled = true;
else Files.delete(path.resolve("inceptum.lock"));
}
catch (IOException e) {
continue;
}
}
if (disabled) ImGui.beginDisabled();
if (ImGui.button(path.getFileName().toString())) {
//TODO extract launch logic to separate class
for (VersionsListInfo version : McApi.getVersions().versions) {
if (version.id.equals(instance.getMinecraftVersion())) {
try {
List<String> args = new ArrayList<>();
args.add("/lib/jvm/java-17-openjdk/bin/java"); //TODO allow selecting vm, detect with System.getProperty("java.home")
VersionInfo info = McApi.getVersionInfo(version);
if (instance.isFabric()) {
FabricMetaApi.addFabric(info, instance.getLoaderVersion());
}
StringBuilder classPath = new StringBuilder();
for (VersionInfo.Library.Downloads.Artifact artifact : VersionInfoLibraryResolver.getRelevant(info)) {
classPath.append(Inceptum.LIBRARIES_DIR.resolve(artifact.path).toAbsolutePath());
classPath.append(':');
}
classPath.append(Inceptum.LIBRARIES_DIR.resolve("net/minecraft/minecraft").resolve(version.id + ".jar").toAbsolutePath());
//TODO -Xms{lowMem} -Xmx{maxMem}
args.addAll(parse(info.arguments.jvm, info, instance, classPath.toString(), path.toAbsolutePath().toString()));
args.add(info.mainClass);
args.addAll(parse(info.arguments.game, info, instance, classPath.toString(), path.toAbsolutePath().toString()));
Inceptum.LOGGER.info(String.join(" ", args));
ProcessBuilder pb = new ProcessBuilder(args.toArray(new String[0]));
pb.directory(path.toFile());
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
Files.writeString(path.resolve("inceptum.lock"), Long.toString(pb.start().pid()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
ImGui.tableNextColumn();
if (ImGui.button("Edit")) {
Inceptum.LOGGER.error("Editing not yet implemented"); //TODO allow changing name (moving), changing version, managing mods etc
}
if (disabled) ImGui.endDisabled();
}
ImGui.endTable();
}
}
private List<String> parse(List<MinecraftArgument> arguments, VersionInfo info, InstanceMeta instance, String classPath, String gameDirectory) {
List<String> res = new ArrayList<>();
for (MinecraftArgument argument : arguments) {
for (String s : argument.arg()) {
//TODO support old versions
AuthInfo authInfo = AccountManager.getSelectedAccount();
res.add(s
// game args
.replace("${auth_player_name}", authInfo.name())
.replace("${version_name}", instance.getMinecraftVersion())
.replace("${game_directory}", gameDirectory)
.replace("${assets_root}", Inceptum.ASSETS_DIR.toAbsolutePath().toString())
.replace("${assets_index_name}", info.assets)
.replace("${auth_uuid}", authInfo.uuid())
.replace("${auth_access_token}", authInfo.accessToken())
.replace("${user_type}", authInfo.userType())
.replace("${version_type}", info.type)
.replace("${resolution_width}", "1920") //TODO has_custom_resolution
.replace("${resolution_height}", "1080") //TODO has_custom_resolution
// jvm args
.replace("${natives_directory}", Inceptum.INSTANCE_DIR.toAbsolutePath().toString())
.replace("${launcher_name}", "Inceptum")
.replace("${launcher_version}", Inceptum.VERSION.version) //TODO automatically fill in
.replace("${classpath}", classPath)
);
}
}
return res;
else InstanceView.draw(paths);
}
}

View File

@ -23,12 +23,13 @@ import java.util.List;
import java.util.Map;
public class NewInstanceWindow extends Window {
public static final int MAX_NAME_LENGTH = 128;
VersionsList manifest = McApi.getVersions();
VersionsListInfo selected;
Map<VersionsListInfo, List<FabricVersionLoaderInfo>> loaderInfoCache = new HashMap<>();
FabricVersionLoaderInfo selectedFabric;
ImInt version = new ImInt(0);
ImString name = new ImString("", 128);
ImString name = new ImString("", MAX_NAME_LENGTH);
ImInt fabricVersion = new ImInt(0);
ImBoolean snapshots = new ImBoolean(Inceptum.CONFIG.snapshots);
ImBoolean fabric = new ImBoolean(true);
@ -67,15 +68,21 @@ public class NewInstanceWindow extends Window {
if (getDefaultName(prev, fabric.get()).equals(name.get()))
name.set(getDefaultName(selected, fabric.get())); //TODO "<ver> (1)" etc if exists
}
if (ImGui.checkbox("Fabric support", fabric)) {
if (getDefaultName(selected, !fabric.get()).equals(name.get()))
name.set(getDefaultName(selected, fabric.get()));
}
if (fabric.get()) {
ImGui.sameLine();
List<FabricVersionLoaderInfo> versions = getFabricLoaderInfo();
if (ImGui.combo("Loader", fabricVersion, versions.stream().map(info -> info.loader.version).toArray(String[]::new))) {
selectedFabric = versions.get(fabricVersion.get());
if (getFabricLoaderInfo().isEmpty()) {
if (fabric.get() && getDefaultName(selected, true).equals(name.get()))
name.set(getDefaultName(selected, false));
fabric.set(false);
} else {
if (ImGui.checkbox("Fabric support", fabric)) {
if (getDefaultName(selected, !fabric.get()).equals(name.get()))
name.set(getDefaultName(selected, fabric.get()));
}
if (fabric.get()) {
ImGui.sameLine();
List<FabricVersionLoaderInfo> versions = getFabricLoaderInfo();
if (ImGui.combo("Loader", fabricVersion, versions.stream().map(info -> info.loader.version).toArray(String[]::new))) {
selectedFabric = versions.get(fabricVersion.get());
}
}
}
//TODO forge

View File

@ -0,0 +1,147 @@
package io.gitlab.jfronny.inceptum.windows.control;
import imgui.ImGui;
import imgui.flag.ImGuiTableFlags;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.model.inceptum.ArtifactInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.mojang.MinecraftArgument;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionsListInfo;
import io.gitlab.jfronny.inceptum.util.ProcessUtils;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.VersionInfoLibraryResolver;
import io.gitlab.jfronny.inceptum.util.api.FabricMetaApi;
import io.gitlab.jfronny.inceptum.util.api.McApi;
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.util.api.account.AuthInfo;
import io.gitlab.jfronny.inceptum.windows.InstanceEditWindow;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
public class InstanceView {
public static void draw(List<Path> paths) {
if (ImGui.beginTable("Instances", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
for (Path path : paths) {
if (Files.exists(path.resolve("inceptum.setup.lock"))) {
ImGui.tableNextColumn();
ImGui.text("Setting up");
ImGui.tableNextColumn();
ImGui.text("This instance is currently being set up");
continue;
}
if (!Files.exists(path.resolve("instance.json"))) {
Inceptum.LOGGER.error("Invalid instance (doesn't contain instance.json): " + path);
continue;
}
InstanceMeta instance;
try {
instance = Utils.loadObject(path.resolve("instance.json"), InstanceMeta.class);
} catch (IOException e) {
Inceptum.LOGGER.error("Could not load instance.json", e);
continue;
}
ImGui.tableNextColumn();
boolean disabled = false;
if (Files.exists(path.resolve("inceptum.lock"))) {
try {
if (ProcessUtils.isProcessAlive(Files.readString(path.resolve("inceptum.lock"))))
disabled = true;
else Files.delete(path.resolve("inceptum.lock"));
} catch (IOException e) {
continue;
}
}
if (disabled) ImGui.beginDisabled();
if (ImGui.button(path.getFileName().toString())) launch(path, instance);
ImGui.tableNextColumn();
if (ImGui.button("Edit")) Inceptum.open(new InstanceEditWindow(path, instance));
if (disabled) ImGui.endDisabled();
}
ImGui.endTable();
}
}
private static void launch(Path path, InstanceMeta instance) {
for (VersionsListInfo version : McApi.getVersions().versions) {
if (version.id.equals(instance.getMinecraftVersion())) {
try {
List<String> args = new ArrayList<>();
args.add(instance.getJava());
//args.add("/lib/jvm/java-17-openjdk/bin/java");
VersionInfo info = McApi.getVersionInfo(version);
if (instance.isFabric()) {
FabricMetaApi.addFabric(info, instance.getLoaderVersion());
}
StringBuilder classPath = new StringBuilder();
for (ArtifactInfo artifact : VersionInfoLibraryResolver.getRelevant(info)) {
classPath.append(Inceptum.LIBRARIES_DIR.resolve(artifact.path).toAbsolutePath());
classPath.append(':');
}
classPath.append(Inceptum.LIBRARIES_DIR.resolve("net/minecraft/minecraft").resolve(version.id + ".jar").toAbsolutePath());
//TODO custom JVM args
if (info.arguments != null) args.addAll(parse(info.arguments.jvm, info, instance, classPath.toString(), path.toAbsolutePath().toString()));
if (instance.minMem != null) args.add("-Xms" + instance.minMem);
if (instance.maxMem != null) args.add("-Xmx" + instance.maxMem);
if (info.minecraftArguments != null) {
args.add("-cp");
args.add(classPath.toString());
args.add("-Djava.library.path=" + Inceptum.NATIVES_DIR.resolve(instance.getMinecraftVersion()).toAbsolutePath());
}
args.add(info.mainClass);
if (info.arguments != null) args.addAll(parse(info.arguments.game, info, instance, classPath.toString(), path.toAbsolutePath().toString()));
else {
for (String s : info.minecraftArguments.split(" ")) {
args.add(expandArg(s, info, instance, classPath.toString(), path.toAbsolutePath().toString()));
}
}
Inceptum.LOGGER.info(String.join(" ", args));
ProcessBuilder pb = new ProcessBuilder(args.toArray(new String[0]));
pb.directory(path.toFile());
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
pb.redirectError(ProcessBuilder.Redirect.INHERIT);
Files.writeString(path.resolve("inceptum.lock"), Long.toString(pb.start().pid()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static List<String> parse(List<MinecraftArgument> arguments, VersionInfo info, InstanceMeta instance, String classPath, String gameDirectory) {
List<String> res = new ArrayList<>();
for (MinecraftArgument argument : arguments) {
for (String s : argument.arg()) {
res.add(expandArg(s, info, instance, classPath, gameDirectory));
}
}
return res;
}
private static String expandArg(String arg, VersionInfo info, InstanceMeta instance, String classPath, String gameDirectory) {
AuthInfo authInfo = AccountManager.getSelectedAccount();
return arg
// game args
.replace("${auth_player_name}", authInfo.name())
.replace("${version_name}", instance.getMinecraftVersion())
.replace("${game_directory}", gameDirectory)
.replace("${assets_root}", Inceptum.ASSETS_DIR.toAbsolutePath().toString())
.replace("${assets_index_name}", info.assets)
.replace("${auth_uuid}", authInfo.uuid())
.replace("${auth_access_token}", authInfo.accessToken())
.replace("${user_type}", authInfo.userType())
.replace("${version_type}", info.type)
.replace("${resolution_width}", "1920") //TODO has_custom_resolution
.replace("${resolution_height}", "1080") //TODO has_custom_resolution
// jvm args
.replace("${natives_directory}", Inceptum.NATIVES_DIR.resolve(instance.getMinecraftVersion()).toAbsolutePath().toString())
.replace("${launcher_name}", "Inceptum")
.replace("${launcher_version}", Inceptum.VERSION.version)
.replace("${classpath}", classPath)
.replace("${user_properties}", "{}");
}
}