Experimental curseforge export support and more refactoring

This commit is contained in:
Johannes Frohnmeyer 2022-01-19 19:14:13 +01:00
parent c944f42c20
commit c03813c446
Signed by: Johannes
GPG Key ID: E76429612C2929F4
44 changed files with 660 additions and 356 deletions

BIN
bingchilling Normal file

Binary file not shown.

View File

@ -35,7 +35,7 @@ allprojects {
}
ext {
lwjglVersion = '3.2.3'
lwjglVersion = '3.3.0'
imguiVersion = '1.86.0'
log4jVersion = '2.14.1'
flavorProp = project.hasProperty('flavor') ? project.getProperty('flavor') : 'custom'
@ -67,7 +67,7 @@ dependencies {
implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")
['', '-opengl', '-glfw'].each {
['', '-opengl', '-glfw', '-tinyfd'].each {
implementation "org.lwjgl:lwjgl$it:$lwjglVersion"
if (flavor == 'windows' || flavor == 'fat') implementation "org.lwjgl:lwjgl$it::natives-windows"
if (flavor == 'linux' || flavor == 'fat') implementation "org.lwjgl:lwjgl$it::natives-linux"

View File

@ -5,7 +5,7 @@ import io.gitlab.jfronny.inceptum.frontend.cli.Commands;
import io.gitlab.jfronny.inceptum.frontend.gui.dialog.AlertWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.dialog.TextBoxWindow;
import io.gitlab.jfronny.inceptum.gson.*;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.model.microsoft.OauthTokenResponse;
import io.gitlab.jfronny.inceptum.model.mojang.MinecraftArgument;
import io.gitlab.jfronny.inceptum.model.mojang.Rules;
@ -24,6 +24,15 @@ public class Inceptum {
public static boolean IS_GUI;
public static void main(String[] args) throws Exception {
if (Wrapper.class.getClassLoader() != Inceptum.class.getClassLoader()) {
throw new IllegalStateException("Mismatching classloader between two classes. Something is wrong here");
}
if (args.length > 0 && args[0].equals("wrapper")) {
if (WrapperStrap.class.getClassLoader() == Inceptum.class.getClassLoader()) {
throw new IllegalStateException("The WrapperStrap classloader does not match the inceptum loader. Are you using the latest wrapper?");
}
}
GsonHolder.registerTypeAdapter(MinecraftArgument.class, new MinecraftArgumentDeserializer());
GsonHolder.registerTypeAdapter(Rules.class, new RulesDeserializer());
GsonHolder.registerTypeAdapter(OauthTokenResponse.class, new OauthTokenResponseDeserializer());

View File

@ -5,7 +5,8 @@ import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.Config;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Steps;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.util.install.Steps;
import io.gitlab.jfronny.inceptum.util.ConfigHolder;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
@ -165,10 +166,15 @@ public class GitCommand extends Command {
}
public static String getName(String url) throws URISyntaxException {
String name;
name = new URIish(url).getHumanishName();
name = name.replaceAll("^\\.*", "");
return name;
try {
String name;
name = new URIish(url).getHumanishName();
name = name.replaceAll("^\\.*", "");
return name;
}
catch (IllegalArgumentException e) {
throw new URISyntaxException(url, "Could not extract name");
}
}
public static void clone(String url, String name) throws GitAPIException, IOException {
@ -189,7 +195,7 @@ public class GitCommand extends Command {
Utils.deleteRecursive(instanceDir);
throw new FileNotFoundException("Invalid repository: Contains no instance.json");
}
Steps.reDownload(instanceDir, state -> {});
Steps.reDownload(instanceDir, Steps.createProcessState());
}
}
}

View File

@ -4,14 +4,13 @@ import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.frontend.cli.BaseInstanceCommand;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Steps;
import io.gitlab.jfronny.inceptum.util.install.Steps;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.InstanceLock;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.launch.ClientLauncher;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.util.launch.InstanceLauncher;
import io.gitlab.jfronny.inceptum.util.InstanceLauncher;
import java.io.IOException;
import java.nio.file.Files;
@ -85,7 +84,7 @@ public class LaunchCommand extends BaseInstanceCommand {
instance.arguments.server.addAll(args.after(0));
}
try {
Steps.reDownload(instanceDir, state -> {});
Steps.reDownload(instanceDir, Steps.createProcessState());
} catch (IOException e) {
e.printStackTrace();
}
@ -98,7 +97,7 @@ public class LaunchCommand extends BaseInstanceCommand {
}
else {
AccountManager.loadAccounts();
ClientLauncher.launch(instanceDir, instance);
InstanceLauncher.launchClient(instanceDir, instance);
}
}
}

View File

@ -4,7 +4,7 @@ import io.gitlab.jfronny.inceptum.frontend.cli.BaseInstanceCommand;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.util.ModManager;
import io.gitlab.jfronny.inceptum.util.ModsDirScanner;
import io.gitlab.jfronny.inceptum.util.Utils;
@ -105,7 +105,7 @@ public class ModCommand extends Command {
mods.add(p);
}
ModsDirScanner mds = ModsDirScanner.get(instancePath.resolve("mods"), meta);
if (!ignoreDependencies && !mds.scanComplete()) {
if (!ignoreDependencies && !mds.isComplete()) {
Utils.LOGGER.error("Scanning mods dir to search for dependencies. This might take a while");
mds.runOnce((path, mod) -> System.out.println("Scanned " + path));
}

View File

@ -8,10 +8,11 @@ import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeMod;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.ModDescription;
import io.gitlab.jfronny.inceptum.model.inceptum.source.CurseforgeModSource;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModDownload;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModrinthModSource;
import io.gitlab.jfronny.inceptum.util.PathUtil;
import io.gitlab.jfronny.inceptum.util.source.CurseforgeModSource;
import io.gitlab.jfronny.inceptum.util.source.ModDownload;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.util.source.ModrinthModSource;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthSearchResult;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthVersion;
import io.gitlab.jfronny.inceptum.util.ModsDirScanner;
@ -131,7 +132,7 @@ public class AddModWindow extends Window {
ModrinthVersion finalLatest = latest;
new Thread(() -> {
try {
download(new ModrinthModSource(finalLatest.id), modsDir.resolve((mod.slug == null ? mod.mod_id : mod.slug) + ".imod"), mds).write();
download(new ModrinthModSource(finalLatest.id), modsDir.resolve((mod.slug == null ? mod.mod_id : mod.slug) + PathUtil.EXT_IMOD), mds).write();
} catch (IOException e) {
Inceptum.showError("Could not download mod", e);
}
@ -199,7 +200,7 @@ public class AddModWindow extends Window {
CurseforgeMod.GameVersionLatestFile finalLatest = latest;
new Thread(() -> {
try {
download(new CurseforgeModSource(mod.id, finalLatest.projectFileId), modsDir.resolve((mod.slug == null ? mod.id : mod.slug) + ".imod"), mds).write();
download(new CurseforgeModSource(mod.id, finalLatest.projectFileId), modsDir.resolve((mod.slug == null ? mod.id : mod.slug) + PathUtil.EXT_IMOD), mds).write();
} catch (IOException e) {
Inceptum.showError("Could not download mod", e);
}
@ -235,7 +236,7 @@ public class AddModWindow extends Window {
ModDownload md = ms.download();
ModDescription manifest = ModDescription.of(md.sha1(), md.murmur2(), ms, mds.getGameVersion());
for (ModSource dependency : ms.getDependencies()) {
DownloadMeta depMan = download(dependency, metaFile.getParent().resolve(dependency.getShortName() + ".imod"), mds);
DownloadMeta depMan = download(dependency, metaFile.getParent().resolve(dependency.getShortName() + PathUtil.EXT_IMOD), mds);
depMan.description.dependents.add(md.file().getFileName().toString());
manifest.dependencies.add(depMan.download.file().getFileName().toString());
depMan.write();

View File

@ -0,0 +1,56 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.dialog.ProcessStateWatcherWindow;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.install.Step;
import io.gitlab.jfronny.inceptum.util.install.Steps;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
public class GuiUtil {
public static void reload() {
try {
List<Path> paths = Utils.ls(MetaHolder.INSTANCE_DIR);
ProcessState state = Steps.createProcessState().extend(paths.size());
InceptumGui.open(new ProcessStateWatcherWindow("Reloading data", "Could not reload resources", state, cToken -> {
for (Path path : paths) {
Steps.reDownload(path, state);
}
}, null));
} catch (IOException e) {
Inceptum.showError("Could not reload", e);
}
}
public static void reload(Path instanceDir) {
ProcessState state = Steps.createProcessState();
InceptumGui.open(new ProcessStateWatcherWindow("Reloading data", "Could not reload resources", state, cToken -> {
Steps.reDownload(instanceDir, state);
}, null));
}
public static void createInstance(SetupStepInfo state) {
ProcessState pState = Steps.createProcessState();
pState.updateStep("Starting install process");
InceptumGui.open(new ProcessStateWatcherWindow("Creating Instance", "Could not create instance", pState, cToken -> {
for (Step step : Steps.STEPS) {
if (cToken.get()) return;
step.execute(state, cToken);
}
Inceptum.showInfo("The instance was successfully created. You can now launch it using the main menu", "Successfully installed");
}, () -> {
try {
Utils.deleteRecursive(MetaHolder.INSTANCE_DIR.resolve(state.name()));
} catch (IOException e) {
Utils.LOGGER.error("Could not delete instance dir", e);
}
}));
}
}

View File

@ -1,72 +0,0 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.model.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Steps;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import java.io.IOException;
import java.nio.file.Files;
import java.util.concurrent.atomic.AtomicBoolean;
public class InstanceCreateProcessWindow extends Window {
private final SetupStepInfo stepInfo;
private final AtomicBoolean finalize = new AtomicBoolean(false);
public InstanceCreateProcessWindow(SetupStepInfo stepInfo) {
super("Creating Instance");
this.stepInfo = stepInfo;
new Thread(this::creationThread).start();
}
@Override
public void draw() {
if (finalize.get()) {
close();
return;
}
ImGui.textUnformatted(stepInfo.currentState().get());
if (ImGui.button("Cancel")) finalize.set(true);
}
private void creationThread() {
if (Files.exists(MetaHolder.INSTANCE_DIR.resolve(stepInfo.name()))) {
finalize.set(true);
return;
}
Utils.LOGGER.info("Starting install process");
try {
for (Step step : Steps.STEPS) {
if (finalize.get()) {
cleanUp();
return;
}
step.execute(stepInfo, finalize);
}
finalize.set(true);
Inceptum.showInfo("The instance was successfully created. You can now launch it using the main menu", "Successfully installed");
close();
} catch (Throwable e) {
Inceptum.showError("Could not create the instance", e);
close();
cleanUp();
}
}
private void cleanUp() {
try {
Utils.deleteRecursive(MetaHolder.INSTANCE_DIR.resolve(stepInfo.name()));
} catch (IOException e) {
Utils.LOGGER.error("Could not delete instance dir", e);
}
}
@Override
public void close() {
super.close();
finalize.set(true);
}
}

View File

@ -7,14 +7,20 @@ import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.InstanceManageControls;
import io.gitlab.jfronny.inceptum.frontend.gui.dialog.ProcessStateWatcherWindow;
import io.gitlab.jfronny.inceptum.model.inceptum.Config;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.util.*;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.IndexDiff;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.util.tinyfd.TinyFileDialogs;
import java.io.IOException;
import java.nio.file.Files;
@ -179,17 +185,9 @@ public class InstanceEditWindow extends Window {
}
}
if (filterUpdates.get() && !updatesFound) continue;
final String disabledSuffix = ".disabled";
final String imodDisabledSuffix = ".disabled.imod";
String fName = mod.path().getFileName().toString();
boolean wasEnabled = !fName.endsWith(disabledSuffix) && !fName.endsWith(imodDisabledSuffix);
boolean wasEnabled = PathUtil.isEnabled(mod.path());
if (ImGui.checkbox("##" + mod.getName(), wasEnabled)) {
if (fName.endsWith(disabledSuffix))
fName = fName.substring(0, fName.length() - disabledSuffix.length());
if (fName.endsWith(imodDisabledSuffix))
fName = fName.substring(0, fName.length() - imodDisabledSuffix.length()) + ".imod";
if (wasEnabled) fName += fName.endsWith(".imod") ? imodDisabledSuffix : disabledSuffix;
Path newSel = mod.path().getParent().resolve(fName);
Path newSel = PathUtil.toggle(mod.path());
try {
Files.move(mod.path(), newSel);
if (mod.path().equals(selected)) selected = newSel;
@ -230,7 +228,7 @@ public class InstanceEditWindow extends Window {
ImGui.sameLine();
if (ImGui.button("Update to " + ms.get().getVersion())) {
try {
Path imodPath = md.imod().isPresent() ? md.imod().get() : path.resolve("mods").resolve(ms.get().getShortName() + ".imod");
Path imodPath = md.imod().isPresent() ? md.imod().get() : path.resolve("mods").resolve(ms.get().getShortName() + PathUtil.EXT_IMOD);
AddModWindow.DownloadMeta dm = AddModWindow.download(ms.get(), imodPath, mds);
Files.delete(md.path());
if (md.imod().isPresent() && Files.exists(md.imod().get()))
@ -266,26 +264,42 @@ public class InstanceEditWindow extends Window {
ImGui.endTabItem();
}
if (git != null && ImGui.beginTabItem("Git")) {
if (ImGui.button("Commit")) {
try {
Inceptum.getInput("Commit message", "Commit at t" + System.currentTimeMillis(), message -> {
try {
git.commit()
.setAll(true)
.setMessage(message)
.setSign(ConfigHolder.CONFIG.git.signCommits)
.setAuthor(ConfigHolder.CONFIG.git.commitUsername, ConfigHolder.CONFIG.git.commitMail)
.setCredentialsProvider(credentialsProvider)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not commit", e);
}
},() -> {});
} catch (IOException e) {
Inceptum.showError("Could not show dialog", e);
}
Status status = null;
try {
status = git.status().call();
} catch (GitAPIException e) {
Utils.LOGGER.error("Could not check repo status", e);
}
if (status != null && status.isClean()) {
ImGui.text("There are un-committed changes");
for (String change : status.getUncommittedChanges()) {
ImGui.bulletText(change);
}
for (String s : status.getUntracked()) {
ImGui.bulletText(s);
}
if (ImGui.button("Commit")) {
try {
Inceptum.getInput("Commit message", "Commit at t" + System.currentTimeMillis(), message -> {
try {
git.commit()
.setAll(true)
.setMessage(message)
.setSign(ConfigHolder.CONFIG.git.signCommits)
.setAuthor(ConfigHolder.CONFIG.git.commitUsername, ConfigHolder.CONFIG.git.commitMail)
.setCredentialsProvider(credentialsProvider)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not commit", e);
}
},() -> {});
} catch (IOException e) {
Inceptum.showError("Could not show dialog", e);
}
}
ImGui.sameLine();
}
ImGui.sameLine();
if (ImGui.button("Push")) {
try {
git.push()
@ -336,6 +350,30 @@ public class InstanceEditWindow extends Window {
}
ImGui.endTabItem();
}
if (ImGui.beginTabItem("Export")) {
if (mds.isComplete()) {
if (ImGui.button("CurseForge")) {
try (MemoryStack stack = MemoryStack.stackPush()) {
PointerBuffer aFilterPatterns = stack.mallocPointer(2);
aFilterPatterns.put(stack.UTF8("*.zip"));
aFilterPatterns.flip();
String p = TinyFileDialogs.tinyfd_saveFileDialog("Export Pack", "", aFilterPatterns, "CurseForge packs (*.zip)");
if (p != null) {
ProcessState state = new ProcessState(InstanceExporter.STEP_COUNT, "Initializing...");
InceptumGui.open(new ProcessStateWatcherWindow("Exporting", "Could not export pack", state, cToken -> {
Path exportPath = Path.of(p);
InstanceExporter.exportCurseZip(state, path, instance, mds, git, exportPath);
Inceptum.showInfo(path.getFileName().toString() + " has been successfully exported to " + exportPath, "Successfully exported");
}, null));
}
}
}
}
else {
ImGui.text("The mods directory scan must be completed.\nThe progress for this can be observed in the mods tab");
}
ImGui.endTabItem();
}
ImGui.endTabBar();
}
}
@ -357,7 +395,7 @@ public class InstanceEditWindow extends Window {
super.close();
if (git != null) git.close();
if (reDownload) {
InceptumGui.open(new ReDownloadWatcherWindow(path));
GuiUtil.reload(path);
}
}

View File

@ -7,7 +7,6 @@ import imgui.type.ImInt;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.InstanceView;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Steps;
import io.gitlab.jfronny.inceptum.util.ConfigHolder;
import io.gitlab.jfronny.inceptum.util.MapAppender;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
@ -46,16 +45,7 @@ public class MainWindow extends Window {
Utils.clearDirectory(MetaHolder.LIBRARIES_DIR, path -> !path.startsWith(MetaHolder.LIBRARIES_DIR.resolve("io/gitlab/jfronny")));
Utils.clearDirectory(MetaHolder.NATIVES_DIR, path -> !path.endsWith("forceload"));
Utils.clearDirectory(MetaHolder.CACHE_DIR);
ReDownloadWatcherWindow window = new ReDownloadWatcherWindow("Re-Downloading");
InceptumGui.open(window);
new Thread(() -> {
try {
Steps.reDownload(window.getConsumer());
window.close();
} catch (IOException e) {
Inceptum.showError("Could not execute refresh task", e);
}
}).start();
GuiUtil.reload();
} catch (IOException e) {
Inceptum.showError("Could not execute refresh task", e);
}

View File

@ -5,19 +5,20 @@ import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.cli.commands.GitCommand;
import io.gitlab.jfronny.inceptum.model.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.frontend.gui.control.InstanceManageControls;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.install.Steps;
import org.eclipse.jgit.api.errors.GitAPIException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.concurrent.atomic.AtomicReference;
public class NewInstanceWindow extends Window {
private final InstanceManageControls imc = new InstanceManageControls(null);
private final ImString inceptumRepo = new ImString(InceptumGui.INPUT_FIELD_LENGTH);
private final ImString inceptumName = new ImString(InceptumGui.INPUT_FIELD_LENGTH);
private String inceptumNamePrev = "";
public NewInstanceWindow() {
super("New Instance");
}
@ -30,10 +31,10 @@ public class NewInstanceWindow extends Window {
imc.versionBox(ver -> {});
imc.nameBox("OK", name -> {
try {
InceptumGui.open(new InstanceCreateProcessWindow(new SetupStepInfo(imc.getVersionInfo(),
GuiUtil.createInstance(new SetupStepInfo(imc.getVersionInfo(),
imc.getLoaderInfo(),
name,
new AtomicReference<>("Initializing"))));
Steps.createProcessState()));
} catch (IOException e) {
Utils.LOGGER.error("Could not initialize instance creation", e);
}
@ -42,9 +43,11 @@ public class NewInstanceWindow extends Window {
ImGui.endTabItem();
}
if (ImGui.beginTabItem("Inceptum")) {
if (ImGui.inputTextWithHint("URL", "Repo to download", inceptumRepo) && (inceptumName.isEmpty() || inceptumName.get().isEmpty())) {
if (ImGui.inputTextWithHint("URL", "Repo to download", inceptumRepo)
&& (inceptumName.isEmpty() || inceptumName.get().isEmpty() || inceptumName.get().equals(inceptumNamePrev))) {
try {
inceptumName.set(GitCommand.CloneCommand.getName(inceptumRepo.get()));
inceptumNamePrev = inceptumName.get();
} catch (URISyntaxException ignored) {
}
}

View File

@ -1,39 +0,0 @@
package io.gitlab.jfronny.inceptum.frontend.gui;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.model.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Steps;
import java.io.IOException;
import java.nio.file.Path;
import java.util.function.Consumer;
public class ReDownloadWatcherWindow extends Window {
private SetupStepInfo info;
public ReDownloadWatcherWindow(String name) {
super(name);
}
public ReDownloadWatcherWindow(Path reDownloadPath) {
this("Reloading data");
new Thread(() -> {
try {
Steps.reDownload(reDownloadPath, getConsumer());
} catch (IOException e) {
Inceptum.showError("Could not reload resources", e);
}
close();
}).start();
}
public Consumer<SetupStepInfo> getConsumer() {
return newInfo -> info = newInfo;
}
@Override
public void draw() {
if (info == null) ImGui.text("Reloading");
else ImGui.textUnformatted(info.currentState().get());
}
}

View File

@ -3,12 +3,12 @@ package io.gitlab.jfronny.inceptum.frontend.gui.control;
import imgui.ImGui;
import imgui.flag.ImGuiTableFlags;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Steps;
import io.gitlab.jfronny.inceptum.util.install.Steps;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.InstanceLock;
import io.gitlab.jfronny.inceptum.util.launch.ClientLauncher;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.frontend.gui.InstanceEditWindow;
import io.gitlab.jfronny.inceptum.util.InstanceLauncher;
import java.io.IOException;
import java.nio.file.Files;
@ -48,11 +48,11 @@ public class InstanceView {
if (runDisabled) ImGui.beginDisabled();
if (ImGui.button(path.getFileName().toString())) {
try {
Steps.reDownload(path, state -> {});
Steps.reDownload(path, Steps.createProcessState());
} catch (IOException e) {
e.printStackTrace();
}
ClientLauncher.launch(path, instance);
InstanceLauncher.launchClient(path, instance);
}
if (runDisabled) ImGui.endDisabled();
ImGui.tableNextColumn();

View File

@ -0,0 +1,56 @@
package io.gitlab.jfronny.inceptum.frontend.gui.dialog;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.frontend.gui.Window;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.util.lambda.ThrowingConsumer;
import org.eclipse.jgit.annotations.Nullable;
import java.util.concurrent.atomic.AtomicBoolean;
public class ProcessStateWatcherWindow extends Window {
private final ProcessState state;
private final Runnable cancel;
private final AtomicBoolean canceled = new AtomicBoolean(false);
private boolean finished;
public ProcessStateWatcherWindow(String title, String errorMessage, ProcessState state, ThrowingConsumer<AtomicBoolean, ?> executor, @Nullable Runnable cancel) {
super(title);
this.state = state;
this.cancel = cancel;
new Thread(() -> {
try {
executor.consume(canceled);
if (canceled.get()) cancel.run();
finished = true;
} catch (Throwable e) {
Inceptum.showError(errorMessage, e);
}
close();
}).start();
}
public ProcessState getState() {
return state;
}
@Override
public void draw() {
ImGui.progressBar(state.getProgress());
ImGui.textUnformatted(state.getCurrentStep());
if (cancel != null && ImGui.button("Cancel")) {
canceled.set(true);
}
}
@Override
public void close() {
if (finished) {
super.close();
}
else if (cancel != null) {
canceled.set(true);
}
}
}

View File

@ -2,7 +2,7 @@ package io.gitlab.jfronny.inceptum.gson;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;

View File

@ -2,10 +2,10 @@ package io.gitlab.jfronny.inceptum.gson;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import io.gitlab.jfronny.inceptum.model.inceptum.source.CurseforgeModSource;
import io.gitlab.jfronny.inceptum.model.inceptum.source.DirectModSource;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModrinthModSource;
import io.gitlab.jfronny.inceptum.util.source.CurseforgeModSource;
import io.gitlab.jfronny.inceptum.util.source.DirectModSource;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.util.source.ModrinthModSource;
import java.io.IOException;
import java.lang.reflect.Type;

View File

@ -0,0 +1,30 @@
package io.gitlab.jfronny.inceptum.model.curseforge;
import java.util.Set;
public class CurseforgeModpackManifest {
public Minecraft minecraft;
public String manifestType;
public Integer manifestVersion;
public String name;
public String version;
public String author;
public Set<File> files;
public String overrides;
public static class Minecraft {
public String version;
public Set<ModLoader> modLoaders;
public static class ModLoader {
public String id;
public Boolean primary;
}
}
public static class File {
public Integer projectID;
public Integer fileID;
public Boolean required;
}
}

View File

@ -1,9 +1,9 @@
package io.gitlab.jfronny.inceptum.model.inceptum;
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeFingerprint;
import io.gitlab.jfronny.inceptum.model.inceptum.source.CurseforgeModSource;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModrinthModSource;
import io.gitlab.jfronny.inceptum.util.source.CurseforgeModSource;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.util.source.ModrinthModSource;
import io.gitlab.jfronny.inceptum.util.HashUtils;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.CurseforgeApi;

View File

@ -0,0 +1,102 @@
package io.gitlab.jfronny.inceptum.util;
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeModpackManifest;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.source.CurseforgeModSource;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.treewalk.FileTreeIterator;
import org.eclipse.jgit.treewalk.TreeWalk;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class InstanceExporter {
public static final int STEP_COUNT = 3;
private static final String OVERRIDES_DIR_DEFAULT = "overrides";
public static void exportCurseZip(ProcessState state, Path instanceDir, InstanceMeta meta, ModsDirScanner mds, Git git, Path exportPath) throws IOException, URISyntaxException, GitAPIException {
if (Files.exists(exportPath)) Files.delete(exportPath);
try (FileSystem fs = Utils.openZipFile(exportPath, true)) {
state.incrementStep("Preparing basic manifest");
CurseforgeModpackManifest manifest = new CurseforgeModpackManifest();
manifest.minecraft = new CurseforgeModpackManifest.Minecraft();
manifest.minecraft.version = meta.getMinecraftVersion();
manifest.minecraft.modLoaders = new LinkedHashSet<>();
if (meta.isFabric()) {
CurseforgeModpackManifest.Minecraft.ModLoader loader = new CurseforgeModpackManifest.Minecraft.ModLoader();
loader.id = "fabric-" + meta.getLoaderVersion();
loader.primary = true;
manifest.minecraft.modLoaders.add(loader);
}
manifest.manifestType = "minecraftModpack";
manifest.manifestVersion = 1;
manifest.name = instanceDir.getFileName().toString();
manifest.version = git.log().setMaxCount(1).call().iterator().next().getId().getName();
manifest.author = ConfigHolder.CONFIG.git.commitUsername;
manifest.overrides = OVERRIDES_DIR_DEFAULT;
Path overrides = fs.getPath(OVERRIDES_DIR_DEFAULT);
Files.createDirectories(overrides);
if (meta.isFabric()) {
state.incrementStep("Adding mods");
manifest.files = new LinkedHashSet<>();
if (!mds.isComplete()) throw new IOException("Mods dir scan is not yet completed");
modsLoop: for (ModsDirScanner.IWModDescription mod : mds.getMods()) {
if (!PathUtil.isEnabled(mod.path())) return;
state.updateStep(mod.path().toString());
if (PathUtil.isImod(mod.path())) {
Set<ModSource> sources = mod.mod().get().sources.keySet();
for (ModSource source : sources) {
if (source instanceof CurseforgeModSource cms) {
CurseforgeModpackManifest.File f = new CurseforgeModpackManifest.File();
f.projectID = cms.getProjectId();
f.fileID = cms.getFileId();
f.required = true;
manifest.files.add(f);
continue modsLoop;
}
}
// Not available on CF
for (ModSource source : sources) {
Path jarPath = source.getJarPath();
Files.copy(jarPath, jarPath.resolve(mod.path().getFileName().toString()));
continue modsLoop;
}
}
Path md = overrides.resolve("mods");
Files.createDirectories(md);
Files.copy(mod.path(), md.resolve(mod.path().getFileName().toString()));
}
}
state.incrementStep("Adding files");
List<Path> discovered = new ArrayList<>();
try (TreeWalk treeWalk = new TreeWalk(git.getRepository())) {
treeWalk.addTree(new FileTreeIterator(git.getRepository()));
treeWalk.setRecursive(false);
while (treeWalk.next()) {
if (treeWalk.getPathString().startsWith("mods")) continue;
discovered.add(instanceDir.resolve(treeWalk.getPathString()));
}
}
for (Path l : discovered) {
String fn = l.getFileName().toString();
if (fn.equals("mods") || fn.startsWith(".")) continue;
state.updateStep(fn);
Path target = overrides.resolve(fn);
if (Files.isDirectory(l)) {
Utils.copyContent(l, target);
}
else Files.copy(l, target);
}
Utils.writeObject(fs.getPath("manifest.json"), manifest);
}
}
}

View File

@ -1,16 +1,17 @@
package io.gitlab.jfronny.inceptum.util.launch;
package io.gitlab.jfronny.inceptum.util;
import io.gitlab.jfronny.inceptum.model.inceptum.install.steps.DownloadLibrariesStep;
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.inceptum.ModDescription;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
import io.gitlab.jfronny.inceptum.util.install.steps.DownloadLibrariesStep;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
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.*;
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 java.io.File;
@ -24,6 +25,38 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
public class InstanceLauncher {
public static void launchClient(Path path, InstanceMeta instance) {
if (AccountManager.accountMissing() && ConfigHolder.CONFIG.enforceAccount) {
Inceptum.showError("You have not set up an account.\nDoing so is required to play Minecraft", "Not authenticated");
return;
}
AuthInfo authInfo = AccountManager.getSelectedAccount();
if (authInfo.equals(AccountManager.NULL_AUTH)) {
try {
String sysUser = System.getProperty("user.name");
if (ConfigHolder.CONFIG.offlineAccountLastName == null)
ConfigHolder.CONFIG.offlineAccountLastName = sysUser;
Inceptum.getInput("User name", ConfigHolder.CONFIG.offlineAccountLastName, name -> {
ConfigHolder.CONFIG.offlineAccountLastName = name.equals(sysUser) ? null : name;
ConfigHolder.saveConfig();
AuthInfo infoNew = new AuthInfo(name, authInfo.uuid(), authInfo.accessToken(), authInfo.userType());
launchClient(path, instance, infoNew);
}, () -> {});
} catch (IOException e) {
Inceptum.showError("Failed to request input", e);
}
}
else launchClient(path, instance, authInfo);
}
private static void launchClient(Path path, InstanceMeta instance, AuthInfo authInfo) {
try {
launch(path, instance, LaunchType.Client, false, authInfo);
} catch (LaunchException | IOException e) {
Inceptum.showError("Could not launch client", e);
}
}
public static void launch(Path instancePath, InstanceMeta instance, LaunchType launchType, boolean restart, AuthInfo authInfo) throws LaunchException, IOException {
if (authInfo == null) throw new LaunchException("authInfo is null");
VersionsListInfo versionDataSimple = getVersion(instance.getMinecraftVersion());
@ -33,7 +66,7 @@ public class InstanceLauncher {
FabricMetaApi.addFabric(versionInfo, instance.getLoaderVersion(), launchType.fabricMetaType);
}
// Ensure libs/assets are present
DownloadLibrariesStep.execute(versionInfo, new AtomicBoolean(false), new AtomicReference<>());
DownloadLibrariesStep.execute(versionInfo, new AtomicBoolean(false), new ProcessState());
// Prepare arguments
List<String> args = new LinkedList<>();
// JVM path
@ -62,10 +95,7 @@ public class InstanceLauncher {
StringBuilder fabricAddMods = new StringBuilder("-Dfabric.addMods=");
Path mods = instancePath.resolve("mods");
if (Files.exists(mods)) {
for (Path imod : Utils.ls(mods, path -> {
String fn = path.getFileName().toString();
return fn.endsWith(".imod") && !fn.endsWith(".disabled.imod");
})) {
for (Path imod : Utils.ls(mods, path -> PathUtil.isImod(path) && PathUtil.isEnabled(path))) {
String fn = imod.getFileName().toString();
if (Files.exists(imod.getParent().resolve(fn.substring(0, fn.length() - 5))))
continue;

View File

@ -1,9 +1,10 @@
package io.gitlab.jfronny.inceptum.util;
import com.google.gson.JsonParseException;
import io.gitlab.jfronny.inceptum.model.fabric.FabricModJson;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.ModDescription;
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.util.lambda.ThrowingConsumer;
import java.io.Closeable;
@ -43,7 +44,7 @@ public class ModsDirScanner implements Closeable {
return mds;
}
public boolean scanComplete() {
public boolean isComplete() {
if (!Files.isDirectory(modsDir)) return true;
try {
for (Path path : Utils.ls(modsDir)) {
@ -68,8 +69,7 @@ public class ModsDirScanner implements Closeable {
Set<IWModDescription> mods = new TreeSet<>();
if (Files.isDirectory(modsDir)) {
for (Path path : Utils.ls(modsDir)) {
String fn = path.getFileName().toString();
if (fn.endsWith(".imod") && Files.exists(path.getParent().resolve(fn.substring(0, fn.length() - 5))))
if (PathUtil.isImod(path) && Files.exists(PathUtil.trimImod(path)))
continue;
mods.add(get(path));
}
@ -107,55 +107,63 @@ public class ModsDirScanner implements Closeable {
return;
}
for (Path mods : Utils.ls(modsDir)) {
if (!Files.exists(mods)) continue;
if (disposed) return;
if (Files.isDirectory(mods)) {
discovered.accept(mods, new IWModDescription(mods));
scannedPaths.add(mods);
} else {
if (mods.toString().endsWith(".jar") || mods.toString().endsWith(".jar.disabled")) {
final var imod = new Object() {
Path i = mods.getParent().resolve(mods.getFileName() + ".imod");
ModDescription md;
};
// mod description
if (!Files.exists(imod.i)) {
Utils.writeObject(imod.i, ModDescription.of(mods));
}
imod.md = Utils.loadObject(imod.i, ModDescription.class);
evaluateSources(imod.md, mods, imod.i, newImod -> {
imod.i = newImod;
imod.md = Utils.loadObject(imod.i, ModDescription.class);
});
discovered.accept(imod.i, new IWModDescription(mods, Optional.of(imod.md), getFmj(mods, imod.md), Optional.of(imod.i)));
scannedPaths.add(mods);
}
else if (mods.toString().endsWith(".imod") || mods.toString().endsWith(".imod.disabled")) {
String fn = mods.getFileName().toString();
Path modFile = mods.getParent().resolve(fn.substring(0, fn.length() - 5));
final var imod = new Object() {
Path i = mods;
ModDescription md = Utils.loadObject(mods, ModDescription.class);
};
evaluateSources(imod.md, modFile, imod.i, newImod -> {
imod.i = newImod;
imod.md = Utils.loadObject(imod.i, ModDescription.class);
});
discovered.accept(imod.i, new IWModDescription(imod.i, Optional.of(imod.md), getFmj(modFile, imod.md), Optional.of(imod.i)));
scannedPaths.add(mods);
}
else {
discovered.accept(mods, new IWModDescription(mods));
scannedPaths.add(mods);
}
}
scanFile(mods, discovered);
}
Thread.sleep(100);
} catch (IOException | URISyntaxException | InterruptedException e) {
} catch (IOException | InterruptedException e) {
Utils.LOGGER.error("Could not list mods", e);
}
}
private void scanFile(Path file, BiConsumer<Path, IWModDescription> discovered) {
if (!Files.exists(file)) return;
if (Files.isDirectory(file)) {
discovered.accept(file, new IWModDescription(file));
scannedPaths.add(file);
return;
}
try {
if (PathUtil.isJar(file)) {
final var imod = new Object() {
Path i = file.getParent().resolve(file.getFileName() + PathUtil.EXT_IMOD);
ModDescription md;
};
// mod description
if (!Files.exists(imod.i)) {
Utils.writeObject(imod.i, ModDescription.of(file));
}
imod.md = Utils.loadObject(imod.i, ModDescription.class);
evaluateSources(imod.md, file, imod.i, newImod -> {
imod.i = newImod;
imod.md = Utils.loadObject(imod.i, ModDescription.class);
});
discovered.accept(imod.i, new IWModDescription(file, Optional.of(imod.md), getFmj(file, imod.md), Optional.of(imod.i)));
scannedPaths.add(file);
return;
}
if (PathUtil.isImod(file)) {
String fn = file.getFileName().toString();
Path modFile = file.getParent().resolve(fn.substring(0, fn.length() - 5));
final var imod = new Object() {
Path i = file;
ModDescription md = Utils.loadObject(file, ModDescription.class);
};
evaluateSources(imod.md, modFile, imod.i, newImod -> {
imod.i = newImod;
imod.md = Utils.loadObject(imod.i, ModDescription.class);
});
discovered.accept(imod.i, new IWModDescription(imod.i, Optional.of(imod.md), getFmj(modFile, imod.md), Optional.of(imod.i)));
scannedPaths.add(file);
return;
}
discovered.accept(file, new IWModDescription(file));
scannedPaths.add(file);
} catch (IOException | URISyntaxException | JsonParseException e) {
Utils.LOGGER.error("Could not scan file for mod info", e);
}
}
private <TEx extends Throwable> void evaluateSources(ModDescription md, Path modFile, Path imodFile, ThrowingConsumer<Path, TEx> imodModified) throws IOException, TEx {
boolean modified = false;
if (md.initialize(getGameVersion())) {
@ -170,7 +178,7 @@ public class ModsDirScanner implements Closeable {
}
if (selectedSource != null && Files.exists(modFile)) {
Files.delete(modFile);
Path newImod = imodFile.getParent().resolve(selectedSource.getShortName() + ".imod");
Path newImod = imodFile.getParent().resolve(selectedSource.getShortName() + PathUtil.EXT_IMOD);
Files.move(imodFile, newImod);
imodFile = newImod;
modified = true;
@ -241,9 +249,7 @@ public class ModsDirScanner implements Closeable {
this(path,
Files.isDirectory(path) ? Optional.empty() : Optional.of(ModDescription.of(path)),
Optional.empty(),
Files.exists(path.getParent().resolve(path.getFileName().toString() + ".imod"))
? Optional.of(path.getParent().resolve(path.getFileName().toString() + ".imod"))
: Optional.empty());
Files.exists(PathUtil.appendImod(path)) ? Optional.of(PathUtil.appendImod(path)) : Optional.empty());
}
/**

View File

@ -0,0 +1,62 @@
package io.gitlab.jfronny.inceptum.util;
import java.nio.file.Path;
public class PathUtil {
public static final String EXT_DISABLED = ".disabled";
public static final String EXT_IMOD = ".imod";
public static final String EXT_IMOD_DISABLED2 = EXT_DISABLED + EXT_IMOD;
public static final String EXT_IMOD_DISABLED = EXT_IMOD + EXT_DISABLED;
public static final String EXT_JAR = ".jar";
public static final String EXT_JAR_DISABLED = EXT_JAR + EXT_DISABLED;
public static boolean isImod(Path p) {
return fn(p).endsWith(EXT_IMOD) || fn(p).endsWith(EXT_IMOD_DISABLED);
}
public static Path trimImod(Path p) {
String fileName = fn(p);
fileName = fileName.endsWith(EXT_IMOD_DISABLED)
? fileName.substring(0, fileName.length() - EXT_IMOD_DISABLED.length())
: fileName.endsWith(EXT_IMOD_DISABLED2)
? fileName.substring(0, fileName.length() - EXT_IMOD_DISABLED2.length())
: fileName.substring(0, fileName.length() - EXT_IMOD.length());
return p.getParent().resolve(fileName);
}
public static Path appendImod(Path p) {
return p.getParent().resolve(fn(p) + EXT_IMOD);
}
public static boolean isJar(Path p) {
return fn(p).endsWith(EXT_JAR) || fn(p).endsWith(EXT_JAR_DISABLED);
}
public static boolean isEnabled(Path p) {
return !fn(p).endsWith(EXT_DISABLED) && !fn(p).endsWith(EXT_IMOD_DISABLED2);
}
public static Path enable(Path p) {
String fileName = fn(p);
fileName = fileName.endsWith(EXT_IMOD_DISABLED2)
? fileName.substring(0, fileName.length() - EXT_IMOD_DISABLED2.length())
: fileName.substring(0, fileName.length() - EXT_DISABLED.length());
return p.getParent().resolve(fileName);
}
public static Path disable(Path p) {
String fileName = fn(p);
fileName = fileName.endsWith(EXT_IMOD)
? fileName.substring(0, fileName.length() - EXT_IMOD.length()) + EXT_IMOD_DISABLED2
: fileName + EXT_DISABLED;
return p.getParent().resolve(fileName);
}
public static Path toggle(Path p) {
return isEnabled(p) ? disable(p) : enable(p);
}
private static String fn(Path p) {
return p.getFileName().toString();
}
}

View File

@ -0,0 +1,44 @@
package io.gitlab.jfronny.inceptum.util;
public class ProcessState {
private final int maxSteps;
private int stepIndex;
private String stepDescription;
public ProcessState() {
this(0, "");
}
public ProcessState(int maxSteps, String defaultText) {
this(maxSteps, defaultText, 0);
}
private ProcessState(int maxSteps, String stepDescription, int stepIndex) {
if (maxSteps < 0) throw new IllegalArgumentException("maxSteps must be a positive integer");
this.maxSteps = maxSteps;
this.stepIndex = stepIndex;
this.stepDescription = stepDescription;
}
public ProcessState extend(int multiplier) {
return new ProcessState(maxSteps * multiplier, stepDescription, stepIndex);
}
public void incrementStep(String description) {
this.stepIndex++;
updateStep(description);
}
public void updateStep(String description) {
this.stepDescription = description;
Utils.LOGGER.info(description);
}
public String getCurrentStep() {
return stepDescription;
}
public float getProgress() {
return ((float)stepIndex) / maxSteps;
}
}

View File

@ -1,17 +1,15 @@
package io.gitlab.jfronny.inceptum.model.inceptum.install;
package io.gitlab.jfronny.inceptum.util.install;
import io.gitlab.jfronny.inceptum.model.inceptum.LoaderInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.util.Utils;
import java.util.concurrent.atomic.AtomicReference;
public record SetupStepInfo(VersionInfo version,
LoaderInfo loader,
String name,
AtomicReference<String> currentState) {
ProcessState currentState) {
public void setState(String state) {
currentState.set(state);
Utils.LOGGER.info(state);
currentState.updateStep(state);
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.inceptum.install;
package io.gitlab.jfronny.inceptum.util.install;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;

View File

@ -1,16 +1,17 @@
package io.gitlab.jfronny.inceptum.model.inceptum.install;
package io.gitlab.jfronny.inceptum.util.install;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.LoaderInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.install.steps.*;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionsListInfo;
import io.gitlab.jfronny.inceptum.util.InstanceLock;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.FabricMetaApi;
import io.gitlab.jfronny.inceptum.util.api.McApi;
import io.gitlab.jfronny.inceptum.util.install.steps.*;
import java.io.IOException;
import java.nio.file.Path;
@ -18,8 +19,6 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
public class Steps {
public static Set<Step> STEPS = new LinkedHashSet<>(List.of(
@ -31,17 +30,21 @@ public class Steps {
new WriteMetadataStep())
);
public static void reDownload(Consumer<SetupStepInfo> update) throws IOException {
public static ProcessState createProcessState() {
return new ProcessState(STEPS.size(), "Initializing");
}
public static void reDownload(ProcessState state) throws IOException {
Utils.ls(MetaHolder.INSTANCE_DIR, p -> {
try {
reDownload(p, update);
reDownload(p, state);
} catch (IOException e) {
Inceptum.showError("Could not execute refresh task", e);
}
});
}
public static void reDownload(Path instance, Consumer<SetupStepInfo> update) throws IOException {
public static void reDownload(Path instance, ProcessState state) throws IOException {
if (InstanceLock.isLocked(instance)) return;
InstanceMeta im = Utils.loadObject(instance.resolve("instance.json"), InstanceMeta.class);
boolean found = false;
@ -53,9 +56,9 @@ public class Steps {
LoaderInfo li = im.isFabric()
? new LoaderInfo(LoaderInfo.Type.Fabric, im.getLoaderVersion())
: LoaderInfo.NONE;
SetupStepInfo info = new SetupStepInfo(vi, li, instance.getFileName().toString(), new AtomicReference<>("Reloading"));
update.accept(info);
SetupStepInfo info = new SetupStepInfo(vi, li, instance.getFileName().toString(), state);
for (Step step : Steps.STEPS) {
state.incrementStep("Starting " + step.getClass().getSimpleName());
step.execute(info, new AtomicBoolean(false));
}
}

View File

@ -1,7 +1,7 @@
package io.gitlab.jfronny.inceptum.model.inceptum.install.steps;
package io.gitlab.jfronny.inceptum.util.install.steps;
import io.gitlab.jfronny.inceptum.model.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.util.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.install.Step;
import io.gitlab.jfronny.inceptum.model.mojang.AssetIndex;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.api.McApi;

View File

@ -1,7 +1,7 @@
package io.gitlab.jfronny.inceptum.model.inceptum.install.steps;
package io.gitlab.jfronny.inceptum.util.install.steps;
import io.gitlab.jfronny.inceptum.model.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.util.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.install.Step;
import io.gitlab.jfronny.inceptum.model.ComparableVersion;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.mojang.MojangFileDownload;

View File

@ -1,7 +1,7 @@
package io.gitlab.jfronny.inceptum.model.inceptum.install.steps;
package io.gitlab.jfronny.inceptum.util.install.steps;
import io.gitlab.jfronny.inceptum.model.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.util.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.install.Step;
import io.gitlab.jfronny.inceptum.model.mojang.JvmFileInfo;
import io.gitlab.jfronny.inceptum.model.mojang.MojangFileDownload;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;

View File

@ -1,7 +1,8 @@
package io.gitlab.jfronny.inceptum.model.inceptum.install.steps;
package io.gitlab.jfronny.inceptum.util.install.steps;
import io.gitlab.jfronny.inceptum.model.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.util.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.install.Step;
import io.gitlab.jfronny.inceptum.model.inceptum.ArtifactInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
@ -15,7 +16,6 @@ import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
public class DownloadLibrariesStep implements Step {
@Override
@ -23,13 +23,12 @@ public class DownloadLibrariesStep implements Step {
execute(info.version(), stopThread, info.currentState());
}
public static void execute(VersionInfo version, AtomicBoolean stopThread, AtomicReference<String> currentState) throws IOException {
public static void execute(VersionInfo version, AtomicBoolean stopThread, ProcessState currentState) throws IOException {
for (ArtifactInfo artifact : VersionInfoLibraryResolver.getRelevant(version)) {
if (stopThread.get()) return;
Path path = MetaHolder.LIBRARIES_DIR.resolve(artifact.path);
if (!Files.exists(path)) {
currentState.set("Downloading library: " + artifact.path);
Utils.LOGGER.info(currentState.get());
currentState.updateStep("Downloading library: " + artifact.path);
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
if (!artifact.url.endsWith(".jar")) {
Utils.LOGGER.info("Not a valid URL for a jar: " + artifact.url);
@ -42,8 +41,7 @@ public class DownloadLibrariesStep implements Step {
}
}
if (artifact.isNative) {
currentState.set("Extracting natives");
Utils.LOGGER.info(currentState.get());
currentState.updateStep("Extracting natives");
try (FileSystem libFs = Utils.openZipFile(path, false)) {
Utils.copyContent(libFs.getPath("."), MetaHolder.NATIVES_DIR.resolve(InstanceMeta.getMinecraftVersion(version.id)));
}

View File

@ -1,7 +1,7 @@
package io.gitlab.jfronny.inceptum.model.inceptum.install.steps;
package io.gitlab.jfronny.inceptum.util.install.steps;
import io.gitlab.jfronny.inceptum.model.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.util.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.install.Step;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.LoaderInfo;
import io.gitlab.jfronny.inceptum.util.InstanceLock;

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.inceptum.model.inceptum.install.steps;
package io.gitlab.jfronny.inceptum.util.install.steps;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.model.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.install.Step;
import io.gitlab.jfronny.inceptum.util.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.install.Step;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.ConfigHolder;
import io.gitlab.jfronny.inceptum.util.InstanceLock;

View File

@ -1,44 +0,0 @@
package io.gitlab.jfronny.inceptum.util.launch;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.ConfigHolder;
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.util.api.account.AuthInfo;
import java.io.IOException;
import java.nio.file.Path;
public class ClientLauncher {
public static void launch(Path path, InstanceMeta instance) {
if (AccountManager.accountMissing() && ConfigHolder.CONFIG.enforceAccount) {
Inceptum.showError("You have not set up an account.\nDoing so is required to play Minecraft", "Not authenticated");
return;
}
AuthInfo authInfo = AccountManager.getSelectedAccount();
if (authInfo.equals(AccountManager.NULL_AUTH)) {
try {
String sysUser = System.getProperty("user.name");
if (ConfigHolder.CONFIG.offlineAccountLastName == null)
ConfigHolder.CONFIG.offlineAccountLastName = sysUser;
Inceptum.getInput("User name", ConfigHolder.CONFIG.offlineAccountLastName, name -> {
ConfigHolder.CONFIG.offlineAccountLastName = name.equals(sysUser) ? null : name;
ConfigHolder.saveConfig();
AuthInfo infoNew = new AuthInfo(name, authInfo.uuid(), authInfo.accessToken(), authInfo.userType());
launchI(path, instance, infoNew);
}, () -> {});
} catch (IOException e) {
Inceptum.showError("Failed to request input", e);
}
}
else launchI(path, instance, authInfo);
}
private static void launchI(Path path, InstanceMeta instance, AuthInfo authInfo) {
try {
InstanceLauncher.launch(path, instance, InstanceLauncher.LaunchType.Client, false, authInfo);
} catch (InstanceLauncher.LaunchException | IOException e) {
Inceptum.showError("Could not launch client", e);
}
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.inceptum.source;
package io.gitlab.jfronny.inceptum.util.source;
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeDependency;
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeFile;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.inceptum.source;
package io.gitlab.jfronny.inceptum.util.source;
import io.gitlab.jfronny.inceptum.util.HashUtils;
import io.gitlab.jfronny.inceptum.util.Utils;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.inceptum.source;
package io.gitlab.jfronny.inceptum.util.source;
import java.nio.file.Path;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.inceptum.source;
package io.gitlab.jfronny.inceptum.util.source;
import io.gitlab.jfronny.inceptum.util.MetaHolder;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.inceptum.source;
package io.gitlab.jfronny.inceptum.util.source;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthMod;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthVersion;

View File

@ -7,7 +7,7 @@ plugins {
}
application {
mainClass = 'io.gitlab.jfronny.inceptum.Wrapper'
mainClass = 'io.gitlab.jfronny.inceptum.WrapperStrap'
}
repositories {

View File

@ -8,6 +8,7 @@ import io.gitlab.jfronny.inceptum.util.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
@ -20,7 +21,7 @@ import java.util.stream.Stream;
public class Wrapper {
private static final Path INCEPTUM_LIB_DIR = MetaHolder.BASE_PATH.resolve("libraries/io/gitlab/jfronny/inceptum/Inceptum");
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
System.out.println("Inceptum Wrapper v" + MetaHolder.VERSION.version + " (" + MetaHolder.VERSION.flavor + ")");
ConfigHolder.load();
if (!Files.exists(INCEPTUM_LIB_DIR)) downloadLatest();
@ -32,15 +33,13 @@ public class Wrapper {
if (localBinary.isEmpty()) {
throw new FileNotFoundException("Could not identify or download a valid binary");
}
List<String> newArgs = new ArrayList<>();
newArgs.add(JvmUtils.getJvm());
newArgs.add("-jar");
newArgs.add(localBinary.get().toString());
newArgs.add("wrapper");
newArgs.addAll(Arrays.asList(args));
new ProcessBuilder(newArgs.toArray(new String[0]))
.inheritIO()
.start();
String[] newArgs = new String[args.length + 1];
newArgs[0] = "wrapper";
System.arraycopy(args, 0, newArgs, 1, args.length);
System.out.println("Starting Inceptum ClassLoader");
WrapperStrap.switchEnv(localBinary.get().toUri().toURL(),
"io.gitlab.jfronny.inceptum.Inceptum",
newArgs);
}
private static void downloadLatest() throws IOException {

View File

@ -0,0 +1,24 @@
package io.gitlab.jfronny.inceptum;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLClassLoader;
public class WrapperStrap {
private static final ClassLoader cl = Thread.currentThread().getContextClassLoader();
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
System.out.println("Starting Inceptum Wrapper ClassLoader");
switchEnv(WrapperStrap.class.getProtectionDomain().getCodeSource().getLocation(),
"io.gitlab.jfronny.inceptum.Wrapper",
args);
}
public static void switchEnv(URL url, String mainClass, String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ClassLoader cl = new URLClassLoader(new URL[] {url}, WrapperStrap.cl);
Thread.currentThread().setContextClassLoader(cl);
cl
.loadClass(mainClass)
.getDeclaredMethod("main", String[].class)
.invoke(null, new Object[] {args});
}
}

View File

@ -180,7 +180,7 @@ public class Utils {
public static void copyContent(Path source, Path destination, CopyOption... copyOptions) throws IOException {
if (!Files.exists(destination)) Files.createDirectories(destination);
if(Files.isDirectory(source)) {
if (Files.isDirectory(source)) {
try (Stream<Path> paths = Files.walk(source)) {
for (Path path : paths.toList()) {
if (source.equals(path)) continue;
@ -190,7 +190,7 @@ public class Utils {
else Files.copy(path, d);
}
}
} else if(Files.exists(source)) {
} else if (Files.exists(source)) {
Path target = destination.resolve(source.getFileName().toString());
if (!Files.exists(target)
|| Arrays.asList(copyOptions).contains(StandardCopyOption.REPLACE_EXISTING))

View File

@ -0,0 +1,5 @@
package io.gitlab.jfronny.inceptum.util.lambda;
public interface ThrowingRunnable<TEx extends Throwable> {
void run() throws TEx;
}