Work through some more TODOs

This commit is contained in:
Johannes Frohnmeyer 2022-01-04 23:32:05 +01:00
parent b3625d46ec
commit f6ac14b266
Signed by: Johannes
GPG Key ID: E76429612C2929F4
20 changed files with 489 additions and 162 deletions

View File

@ -36,7 +36,7 @@ allprojects {
ext {
lwjglVersion = '3.2.3'
imguiVersion = '1.85.1'
imguiVersion = '1.86.0'
log4jVersion = '2.14.1'
flavorProp = project.hasProperty('flavor') ? project.getProperty('flavor') : 'custom'
flavor = flavorProp
@ -61,7 +61,7 @@ if (flavor == 'custom') {
dependencies {
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'org.slf4j:slf4j-api:1.7.32'
implementation 'ch.qos.logback:logback-classic:1.2.9'
implementation 'ch.qos.logback:logback-classic:1.2.10'
implementation 'org.eclipse.jgit:org.eclipse.jgit:6.0.0.202111291000-r'
implementation project(":wrapper")

View File

@ -12,6 +12,7 @@ import io.gitlab.jfronny.inceptum.model.microsoft.OauthTokenResponse;
import io.gitlab.jfronny.inceptum.model.mojang.MinecraftArgument;
import io.gitlab.jfronny.inceptum.model.mojang.Rules;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.ModsDirScanner;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.McApi;
import io.gitlab.jfronny.inceptum.windows.dialog.AlertWindow;
@ -94,6 +95,7 @@ public class Inceptum {
}
command.invoke();
ModsDirScanner.closeAll();
}
public static void saveConfig() {

View File

@ -6,6 +6,9 @@ import imgui.flag.ImGuiConfigFlags;
import imgui.gl3.ImGuiImplGl3;
import imgui.glfw.ImGuiImplGlfw;
import io.gitlab.jfronny.inceptum.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.ModsDirScanner;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.windows.Window;
import org.lwjgl.glfw.Callbacks;
@ -20,6 +23,8 @@ import org.lwjgl.system.MemoryUtil;
import java.io.IOException;
import java.io.InputStream;
import java.nio.IntBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
@ -37,6 +42,14 @@ public class InceptumGui {
public static void main(CommandArgs args, Runnable exec) {
AccountManager.loadAccounts();
Inceptum.LOGGER.info("Initializing UI");
try {
for (Path path : Utils.ls(Inceptum.INSTANCE_DIR)) {
if (Files.exists(path.resolve("instance.json")))
ModsDirScanner.get(path, Utils.loadObject(path.resolve("instance.json"), InstanceMeta.class)).start();
}
} catch (IOException e) {
Inceptum.LOGGER.error("Could not initialize MDS");
}
init();
exec.run();
run();
@ -63,8 +76,6 @@ public class InceptumGui {
public static void dispose() {
imGuiGl3.dispose();
imGuiGlfw.dispose();
//TODO figure out why this is a problem
//ImGui.destroyContext();
Callbacks.glfwFreeCallbacks(handle);
GLFW.glfwDestroyWindow(handle);
GLFW.glfwTerminate();

View File

@ -0,0 +1,55 @@
package io.gitlab.jfronny.inceptum.cli;
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;
import java.util.List;
public abstract class BaseInstanceCommand extends Command {
public BaseInstanceCommand(String help, String usage, String... aliases) {
super(help, mutateUsage(usage), aliases);
}
public BaseInstanceCommand(String help, String usage, List<String> aliases, List<Command> subCommands) {
super(help, mutateUsage(usage), aliases, subCommands);
}
private static String mutateUsage(String usage) {
StringBuilder sb = new StringBuilder();
for (String s : usage.split("\n")) {
if (s.isBlank())
sb.append("\n<instance>");
else
sb.append("\n<instance> ").append(s);
}
return sb.substring(1);
}
@Override
protected void invoke(CommandArgs args) {
if (args.length == 0) {
Inceptum.LOGGER.error("You must specify an instance to commit in");
return;
}
Path instancePath = Inceptum.INSTANCE_DIR.resolve(args.get(0));
Path instanceMetaPath = instancePath.resolve("instance.json");
if (!Files.exists(instanceMetaPath)) {
Inceptum.LOGGER.error("Invalid instance: \"" + args.get(0) + "\"");
return;
}
InstanceMeta meta;
try {
meta = Utils.loadObject(instanceMetaPath, InstanceMeta.class);
} catch (IOException e) {
Inceptum.LOGGER.error("Could not read instance metadata", e);
return;
}
invoke(args.subArgs(), instancePath, meta);
}
protected abstract void invoke(CommandArgs args, Path instancePath, InstanceMeta meta);
}

View File

@ -13,6 +13,7 @@ public class Commands {
GUI_COMMAND,
new LaunchCommand(),
new ListCommand(),
new ModCommand(),
new GitCommand(),
new UpdateCheckCommand(),
new JvmStateCommand(),

View File

@ -1,10 +1,12 @@
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.cli.BaseInstanceCommand;
import io.gitlab.jfronny.inceptum.cli.Command;
import io.gitlab.jfronny.inceptum.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.install.Steps;
import io.gitlab.jfronny.inceptum.model.inceptum.Config;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.Utils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
@ -34,32 +36,22 @@ public class GitCommand extends Command {
Inceptum.LOGGER.error("No known git command was specified");
}
private static abstract class BaseGitCommand extends Command {
private static abstract class BaseGitCommand extends BaseInstanceCommand {
public BaseGitCommand(String help, String usage, String... aliases) {
super(help, usage, aliases);
}
@Override
protected void invoke(CommandArgs args) {
if (args.length == 0) {
Inceptum.LOGGER.error("You must specify an instance to commit in");
return;
}
Path instancePath = Inceptum.INSTANCE_DIR.resolve(args.get(0));
if (!Files.exists(instancePath.resolve("instance.json"))) {
Inceptum.LOGGER.error("Invalid instance: \"" + args.get(0) + "\"");
return;
}
protected void invoke(CommandArgs args, Path instancePath, InstanceMeta meta) {
try (Git git = Git.open(instancePath.toFile())) {
Config.GitConfig config = Inceptum.CONFIG.git.get(instancePath.getFileName().toString());
if (config == null) {
config = new Config.GitConfig();
Inceptum.saveConfig();
Config.GitConfig.GitAuth config = Inceptum.CONFIG.git.instanceAuths.get(instancePath.getFileName().toString());
boolean changed = false;
if (Inceptum.CONFIG.git == null) {
Inceptum.CONFIG.git = new Config.GitConfig();
changed = true;
}
if (config.authorName == null) config.authorName = "Inceptum";
if (config.authorMail == null) config.authorMail = "inceptum@jfronny.gitlab.io";
if (config.sign == null) config.sign = false;
invoke(args.subArgs(), instancePath, git, config, config.username != null && config.password != null
if (changed) Inceptum.saveConfig();
invoke(args.subArgs(), instancePath, git, config.username != null && config.password != null
? new UsernamePasswordCredentialsProvider(config.username, config.password)
: CredentialsProvider.getDefault());
} catch (IOException e) {
@ -67,24 +59,24 @@ public class GitCommand extends Command {
}
}
protected abstract void invoke(CommandArgs args, Path instancePath, Git git, Config.GitConfig config, CredentialsProvider credentials);
protected abstract void invoke(CommandArgs args, Path instancePath, Git git, CredentialsProvider credentials);
}
private static class CommitCommand extends BaseGitCommand {
public CommitCommand() {
super("Adds and commits all changes in the instance.", "<instance> [message...]", "commit");
super("Adds and commits all changes in the instance.", "[message...]", "commit");
}
@Override
protected void invoke(CommandArgs args, Path instancePath, Git git, Config.GitConfig config, CredentialsProvider credentials) {
protected void invoke(CommandArgs args, Path instancePath, Git git, CredentialsProvider credentials) {
try {
git.commit()
.setAll(true)
.setMessage(args.length > 1
? String.join(" ", args.getArgs())
: "Commit at t" + System.currentTimeMillis())
.setSign(config.sign)
.setAuthor(config.authorName, config.authorMail)
.setSign(Inceptum.CONFIG.git.signCommits)
.setAuthor(Inceptum.CONFIG.git.commitUsername, Inceptum.CONFIG.git.commitMail)
.setCredentialsProvider(credentials)
.call();
} catch (GitAPIException e) {
@ -95,11 +87,11 @@ public class GitCommand extends Command {
private static class PushCommand extends BaseGitCommand {
public PushCommand() {
super("Pushes the current branch to the configured remote", "<instance>", "push");
super("Pushes the current branch to the configured remote", "", "push");
}
@Override
protected void invoke(CommandArgs args, Path instancePath, Git git, Config.GitConfig config, CredentialsProvider credentials) {
protected void invoke(CommandArgs args, Path instancePath, Git git, CredentialsProvider credentials) {
try {
git.push()
.setCredentialsProvider(credentials)
@ -112,11 +104,11 @@ public class GitCommand extends Command {
private static class PullCommand extends BaseGitCommand {
public PullCommand() {
super("Pulls remote changes into the current branch and working tree", "<instance>", "pull");
super("Pulls remote changes into the current branch and working tree", "", "pull");
}
@Override
protected void invoke(CommandArgs args, Path instancePath, Git git, Config.GitConfig config, CredentialsProvider credentials) {
protected void invoke(CommandArgs args, Path instancePath, Git git, CredentialsProvider credentials) {
try {
git.pull()
.setRebase(true)
@ -130,11 +122,11 @@ public class GitCommand extends Command {
private static class ResetCommand extends BaseGitCommand {
public ResetCommand() {
super("Resets the current instance state to the last commit", "<instance>", "reset");
super("Resets the current instance state to the last commit", "", "reset");
}
@Override
protected void invoke(CommandArgs args, Path instancePath, Git git, Config.GitConfig config, CredentialsProvider credentials) {
protected void invoke(CommandArgs args, Path instancePath, Git git, CredentialsProvider credentials) {
try {
git.checkout()
.setAllPaths(true)
@ -197,11 +189,8 @@ public class GitCommand extends Command {
}
return;
}
Config.GitConfig config = new Config.GitConfig();
Inceptum.CONFIG.git.put(name, config);
Inceptum.saveConfig();
try {
Steps.reDownload(instanceDir);
Steps.reDownload(instanceDir, state -> {});
} catch (IOException e) {
e.printStackTrace();
}

View File

@ -1,6 +1,7 @@
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.cli.BaseInstanceCommand;
import io.gitlab.jfronny.inceptum.cli.Command;
import io.gitlab.jfronny.inceptum.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.install.Steps;
@ -18,13 +19,13 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class LaunchCommand extends Command {
public class LaunchCommand extends BaseInstanceCommand {
private final boolean server;
private final boolean restart;
public LaunchCommand() {
super("Launches an instance of the game (client by default). Non-blocking (batch commands will continue if this is ran)",
"<instance> [game arguments...]",
"[game arguments...]",
List.of("run", "launch", "start"),
List.of(
new LaunchCommand("Explicitly launch a client", "client", false, false),
@ -37,13 +38,13 @@ public class LaunchCommand extends Command {
}
private LaunchCommand(String help, String name, boolean server, boolean restart, Command... subCommands) {
super(help, "<instance> [game arguments...]", List.of(name), Arrays.asList(subCommands));
super(help, "[game arguments...]", List.of(name), Arrays.asList(subCommands));
this.server = server;
this.restart = restart;
}
@Override
protected void invoke(CommandArgs args) {
protected void invoke(CommandArgs args, Path instancePath, InstanceMeta meta) {
if (args.length == 0) {
Inceptum.LOGGER.error("You must provide an instance name or path");
return;
@ -83,7 +84,7 @@ public class LaunchCommand extends Command {
instance.arguments.server.addAll(args.after(0));
}
try {
Steps.reDownload(instanceDir);
Steps.reDownload(instanceDir, state -> {});
} catch (IOException e) {
e.printStackTrace();
}

View File

@ -0,0 +1,122 @@
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.cli.BaseInstanceCommand;
import io.gitlab.jfronny.inceptum.cli.Command;
import io.gitlab.jfronny.inceptum.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.ModManager;
import io.gitlab.jfronny.inceptum.util.ModsDirScanner;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class ModCommand extends Command {
//TODO add (search), update
public ModCommand() {
super("Allows managing mods in instances", "", List.of("mod"), List.of(
new ModListCommand(),
new ModRemoveCommand()
));
}
@Override
protected void invoke(CommandArgs args) {
Inceptum.LOGGER.error("No known mod command was specified");
}
public static class ModListCommand extends BaseInstanceCommand {
private final boolean filterUpdatable;
public ModListCommand() {
this("Lists the mods in an instance", List.of("list", "ls"), List.of(
new ModListCommand("List only updatable mods", List.of("updatable"), List.of(), true)
), false);
}
private ModListCommand(String help, List<String> aliases, List<Command> subCommands, boolean filterUpdatable) {
super(help, "", aliases, subCommands);
this.filterUpdatable = filterUpdatable;
}
@Override
protected void invoke(CommandArgs args, Path instancePath, InstanceMeta meta) {
if (!meta.isFabric()) {
System.err.println("This is not a fabric instance");
return;
}
System.out.println("Scanning installed mods, this might take a while");
ModsDirScanner mds = ModsDirScanner.get(instancePath.resolve("mods"), meta);
mds.runOnce((path, mod) -> {
boolean hasSources = mod.mod().isPresent() && !mod.mod().get().sources.isEmpty();
boolean updatable = hasSources && mod.mod().get().sources.values().stream().anyMatch(Optional::isPresent);
if (filterUpdatable && !updatable) return;
System.out.println("- " + path.getFileName().toString());
System.out.println(" " + mod.getName());
for (String s : mod.getDescription()) {
System.out.println(" " + s);
}
if (hasSources) {
System.out.println(" Sources:");
for (Map.Entry<ModSource, Optional<ModSource>> entry : mod.mod().get().sources.entrySet()) {
System.out.println(" - " + entry.getKey().getName() + " (" + entry.getKey().getVersion() + ")");
System.out.println(" Local: " + entry.getKey().getJarPath().toString());
if (entry.getValue().isPresent())
System.out.println(" Updatable to: " + entry.getValue().get().getVersion());
}
}
});
}
}
public static class ModRemoveCommand extends BaseInstanceCommand {
private final boolean ignoreDependencies;
public ModRemoveCommand() {
this("Removes a mod from an instance", List.of("remove", "delete", "rm", "del"), List.of(
new ModRemoveCommand("Skip dependency checks", List.of("ignore-dependencies"), List.of(), true)
), false);
}
private ModRemoveCommand(String help, List<String> aliases, List<Command> subCommands, boolean ignoreDependencies) {
super(help, "<mod file>...", aliases, subCommands);
this.ignoreDependencies = ignoreDependencies;
}
@Override
protected void invoke(CommandArgs args, Path instancePath, InstanceMeta meta) {
if (!meta.isFabric()) {
Inceptum.LOGGER.error("This is not a fabric instance");
return;
}
if (args.length == 0) {
Inceptum.LOGGER.error("You must specify mods to remove");
return;
}
Set<Path> mods = new HashSet<>();
for (String arg : args) {
Path p = instancePath.resolve("mods").resolve(arg);
if (!Files.exists(p)) {
Inceptum.LOGGER.error("Nonexistant mod file: " + p);
return;
}
mods.add(p);
}
ModsDirScanner mds = ModsDirScanner.get(instancePath.resolve("mods"), meta);
if (!ignoreDependencies && !mds.scanComplete()) {
Inceptum.LOGGER.error("Scanning mods dir to search for dependencies. This might take a while");
mds.runOnce((path, mod) -> System.out.println("Scanned " + path));
}
for (Path mod : mods) {
try {
ModManager.delete(new ModsDirScanner.IWModDescription(mod), instancePath.resolve("mods"), mds);
} catch (IOException e) {
Inceptum.LOGGER.error("Could not delete " + mod, e);
return;
}
}
}
}
}

View File

@ -18,6 +18,7 @@ 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(
@ -29,17 +30,17 @@ public class Steps {
new WriteMetadataStep())
);
public static void reDownload() throws IOException {
public static void reDownload(Consumer<SetupStepInfo> update) throws IOException {
Utils.ls(Inceptum.INSTANCE_DIR, p -> {
try {
reDownload(p);
reDownload(p, update);
} catch (IOException e) {
Inceptum.showError("Could not execute refresh task", e);
}
});
}
public static void reDownload(Path instance) throws IOException {
public static void reDownload(Path instance, Consumer<SetupStepInfo> update) throws IOException {
if (InstanceLock.isLocked(instance)) return;
InstanceMeta im = Utils.loadObject(instance.resolve("instance.json"), InstanceMeta.class);
boolean found = false;
@ -52,6 +53,7 @@ public class Steps {
? new LoaderInfo(LoaderInfo.Type.Fabric, im.getLoaderVersion())
: LoaderInfo.NONE;
SetupStepInfo info = new SetupStepInfo(vi, li, instance.getFileName().toString(), new AtomicReference<>("Reloading"));
update.accept(info);
for (Step step : Steps.STEPS) {
step.execute(info, new AtomicBoolean(false));
}

View File

@ -56,7 +56,7 @@ public class WriteMetadataStep implements Step {
.setAll(true)
.setMessage("Initial commit")
.setSign(false)
.setAuthor("Inceptum", "inceptum@jfronny.gitlab.io")
.setAuthor(Inceptum.CONFIG.git.commitUsername, Inceptum.CONFIG.git.commitMail)
.call();
} catch (GitAPIException e) {
Inceptum.showError("Could not initialize Git", e);

View File

@ -1,6 +1,5 @@
package io.gitlab.jfronny.inceptum.model.inceptum;
import java.util.HashMap;
import java.util.Map;
public class Config {
@ -10,13 +9,17 @@ public class Config {
public String lastAccount;
public String offlineAccountLastName = null;
public UpdateChannel channel = UpdateChannel.Stable;
public Map<String, GitConfig> git = new HashMap<>();
public GitConfig git = new GitConfig();
public static class GitConfig {
public String username;
public String password;
public Boolean sign = false;
public String authorName;
public String authorMail;
public Map<String, GitAuth> instanceAuths;
public String commitUsername = "Inceptum";
public String commitMail = "inceptum@jfronny.gitlab.io";
public Boolean signCommits = false;
public static class GitAuth {
public String username;
public String password;
}
}
}

View File

@ -3,6 +3,7 @@ package io.gitlab.jfronny.inceptum.model.inceptum;
import io.gitlab.jfronny.inceptum.gson.GsonIgnore;
import java.util.List;
import java.util.Objects;
public class InstanceMeta {
@GsonIgnore public static final String floaderPrefix = "fabric-loader-";
@ -32,5 +33,37 @@ public class InstanceMeta {
public List<String> jvm;
public List<String> client;
public List<String> server;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Arguments arguments = (Arguments) o;
return Objects.equals(jvm, arguments.jvm)
&& Objects.equals(client, arguments.client)
&& Objects.equals(server, arguments.server);
}
@Override
public int hashCode() {
return Objects.hash(jvm, client, server);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InstanceMeta that = (InstanceMeta) o;
return Objects.equals(version, that.version)
&& Objects.equals(java, that.java)
&& Objects.equals(minMem, that.minMem)
&& Objects.equals(maxMem, that.maxMem)
&& Objects.equals(arguments, that.arguments);
}
@Override
public int hashCode() {
return Objects.hash(version, java, minMem, maxMem, arguments);
}
}

View File

@ -47,7 +47,6 @@ public final class CurseforgeModSource implements ModSource {
@Override
public Optional<ModSource> getUpdate(String gameVersion) throws IOException {
//TODO test
for (CurseforgeMod.GameVersionLatestFile file : mod.gameVersionLatestFiles) {
if (file.gameVersion.equals(gameVersion)) {
return file.projectFileId == fileId

View File

@ -0,0 +1,24 @@
package io.gitlab.jfronny.inceptum.util;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class ModManager {
public static void delete(ModsDirScanner.IWModDescription md, Path modsDirectory, ModsDirScanner mds) throws IOException {
Utils.deleteRecursive(md.path());
if (md.imod().isPresent() && Files.exists(md.imod().get())) Files.delete(md.imod().get());
if (md.mod().isPresent()) {
for (String dependency : md.mod().get().dependencies) {
Path dep = modsDirectory.resolve(dependency);
ModsDirScanner.IWModDescription dmd = mds.get(dep);
if (dmd.mod().isPresent()) {
dmd.mod().get().dependencies.remove(md.path().getFileName().toString());
if (dmd.mod().get().dependencies.isEmpty()) delete(dmd, modsDirectory, mds);
else if (dmd.imod().isPresent())
Utils.writeObject(dmd.imod().get(), dmd.mod().get());
}
}
}
}
}

View File

@ -14,8 +14,10 @@ import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.BiConsumer;
public class ModsDirScanner implements Closeable {
private static final Map<Path, ModsDirScanner> scanners = new HashMap<>();
private final Map<Path, IWModDescription> descriptions = new HashMap<>();
private final Set<Path> scannedPaths = new HashSet<>();
private final Thread th;
@ -23,14 +25,39 @@ public class ModsDirScanner implements Closeable {
private final InstanceMeta instance;
private boolean disposed = false;
public ModsDirScanner(Path modsDir, InstanceMeta instance) {
private ModsDirScanner(Path modsDir, InstanceMeta instance) {
this.modsDir = modsDir;
this.instance = instance;
this.th = new Thread(this::scanTaskInternal);
}
public static ModsDirScanner get(Path modsDir, InstanceMeta instance) {
if (scanners.containsKey(modsDir)) {
ModsDirScanner mds = scanners.get(modsDir);
if (mds.instance.equals(instance))
return mds;
mds.close();
}
ModsDirScanner mds = new ModsDirScanner(modsDir, instance);
scanners.put(modsDir, mds);
return mds;
}
public boolean scanComplete() {
if (!Files.isDirectory(modsDir)) return true;
try {
for (Path path : Utils.ls(modsDir)) {
if (!descriptions.containsKey(path)) return false;
}
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
public void start() {
th.start();
if (!th.isAlive())
th.start();
}
public String getGameVersion() {
@ -69,60 +96,63 @@ public class ModsDirScanner implements Closeable {
private void scanTaskInternal() {
while (!disposed) {
try {
if (!Files.isDirectory(modsDir)) {
Thread.sleep(5000);
continue;
}
for (Path mods : Utils.ls(modsDir)) {
if (!Files.exists(mods)) continue;
if (disposed) return;
if (Files.isDirectory(mods)) {
descriptions.put(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));
}
runOnce(descriptions::put);
}
}
public void runOnce(BiConsumer<Path, IWModDescription> discovered) {
try {
if (!Files.isDirectory(modsDir)) {
Thread.sleep(5000);
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);
evaluateSources(imod.md, mods, imod.i, newImod -> {
imod.i = newImod;
imod.md = Utils.loadObject(imod.i, ModDescription.class);
});
descriptions.put(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")) {
//TODO ensure this is not called while downloading a pack
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);
});
descriptions.put(imod.i, new IWModDescription(imod.i, Optional.of(imod.md), getFmj(modFile, imod.md), Optional.of(imod.i)));
scannedPaths.add(mods);
}
else {
descriptions.put(mods, new IWModDescription(mods));
scannedPaths.add(mods);
}
});
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);
}
}
Thread.sleep(100);
} catch (IOException | URISyntaxException | InterruptedException e) {
Inceptum.LOGGER.error("Could not list mods", e);
}
Thread.sleep(100);
} catch (IOException | URISyntaxException | InterruptedException e) {
Inceptum.LOGGER.error("Could not list mods", e);
}
}
@ -134,7 +164,6 @@ public class ModsDirScanner implements Closeable {
}
ModSource selectedSource = null;
for (ModSource source : md.sources.keySet()) {
//TODO properly cache
source.getUpdate(getGameVersion());
if (!Files.exists(source.getJarPath())) source.download();
selectedSource = source;
@ -163,9 +192,16 @@ public class ModsDirScanner implements Closeable {
}
}
public static void closeAll() {
for (ModsDirScanner value : scanners.values().toArray(ModsDirScanner[]::new)) {
value.close();
}
}
@Override
public void close() {
disposed = true;
scanners.remove(modsDir);
}
public record IWModDescription(Path path, Optional<ModDescription> mod, Optional<FabricModJson> fmj, Optional<Path> imod) implements Comparable<IWModDescription> {
@ -202,7 +238,12 @@ public class ModsDirScanner implements Closeable {
* @param path The path of the mod entry
*/
public IWModDescription(Path path) {
this(path, Files.isDirectory(path) ? Optional.empty() : Optional.of(ModDescription.of(path)), Optional.empty(), Optional.empty());
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());
}
/**

View File

@ -33,6 +33,7 @@ public class AddModWindow extends Window {
private int mrPage = 0;
private ModrinthSearchResult mr = null;
private List<CurseforgeMod> cf = null;
public AddModWindow(Path modsDir, InstanceMeta instance, ModsDirScanner mds) {
super(modsDir.getParent().getFileName().toString() + " - Add Mods");
this.modsDir = modsDir;
@ -41,10 +42,19 @@ public class AddModWindow extends Window {
}
private void reSearch() throws IOException {
//TODO move to thread maybe
mr = ModrinthApi.search(query.get(), mrPage, instance.getMinecraftVersion());
cf = CurseforgeApi.search(instance.getMinecraftVersion(), query.get(), cfPage, "Popularity");
//if (mr.hits.isEmpty()) page = 0;
String query = this.query.get();
new Thread(() -> {
try {
ModrinthSearchResult ms = ModrinthApi.search(query, mrPage, instance.getMinecraftVersion());
if (!this.query.get().equals(query)) return;
mr = ms;
List<CurseforgeMod> cs = CurseforgeApi.search(instance.getMinecraftVersion(), query, cfPage, "Popularity");
if (!this.query.get().equals(query)) return;
cf = cs;
} catch (IOException e) {
e.printStackTrace();
}
}, "search" + query).start();
}
@Override
@ -117,8 +127,14 @@ public class AddModWindow extends Window {
Inceptum.showError("No valid version could be identified for this mod", "No version found");
}
else {
//TODO don't block
download(new ModrinthModSource(latest.id), modsDir.resolve((mod.slug == null ? mod.mod_id : mod.slug) + ".imod"), mds).write();
ModrinthVersion finalLatest = latest;
new Thread(() -> {
try {
download(new ModrinthModSource(finalLatest.id), modsDir.resolve((mod.slug == null ? mod.mod_id : mod.slug) + ".imod"), mds).write();
} catch (IOException e) {
Inceptum.showError("Could not download mod", e);
}
}).start();
}
}
}
@ -179,8 +195,14 @@ public class AddModWindow extends Window {
Inceptum.showError("No valid version could be identified for this mod", "No version found");
}
else {
//TODO don't block
download(new CurseforgeModSource(mod.id, latest.projectFileId), modsDir.resolve((mod.slug == null ? mod.id : mod.slug) + ".imod"), mds).write();
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();
} catch (IOException e) {
Inceptum.showError("Could not download mod", e);
}
}).start();
}
}
}

View File

@ -6,14 +6,10 @@ import imgui.type.ImBoolean;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.install.Steps;
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.InstanceLock;
import io.gitlab.jfronny.inceptum.util.JvmUtils;
import io.gitlab.jfronny.inceptum.util.ModsDirScanner;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.*;
import io.gitlab.jfronny.inceptum.windows.control.InstanceManageControls;
import java.io.IOException;
@ -33,29 +29,24 @@ public class InstanceEditWindow extends Window {
private final ImString customJavaPath = new ImString(512);
private final ImString gitUsername = new ImString(512);
private final ImString gitPassword = new ImString(512);
private final ImBoolean gitSign = new ImBoolean();
private final ImString gitAuthorName = new ImString(512);
private final ImString gitAuthorMail = new ImString(512);
private final ModsDirScanner mds;
private Path selected = null;
private boolean reDownload = false;
private boolean lastTabWasMods = false;
public InstanceEditWindow(Path path, InstanceMeta instance) {
super(path.getFileName().toString() + " - Edit");
name = path.getFileName().toString();
this.path = path;
this.instance = instance;
mds = new ModsDirScanner(path.resolve("mods"), instance);
mds = ModsDirScanner.get(path.resolve("mods"), instance);
mds.start();
customJava = new ImBoolean(instance.java != null);
imc = new InstanceManageControls(instance);
if (Inceptum.CONFIG.git.containsKey(name)) {
Config.GitConfig config = Inceptum.CONFIG.git.get(name);
if (Inceptum.CONFIG.git.instanceAuths.containsKey(name)) {
Config.GitConfig.GitAuth config = Inceptum.CONFIG.git.instanceAuths.get(name);
gitUsername.set(config.username);
gitPassword.set(config.password);
gitSign.set(config.sign);
gitAuthorName.set(config.authorName);
gitAuthorMail.set(config.authorMail);
}
}
@ -73,6 +64,7 @@ public class InstanceEditWindow extends Window {
ImGui.text("Could not read lock state on this instance");
Inceptum.LOGGER.error("Could not read lock state", e);
}
lastTabWasMods = false;
if (ImGui.beginTabBar("InstanceEdit" + path)) {
if (ImGui.beginTabItem("General")) {
if (ImGui.button("Open Directory")) {
@ -117,8 +109,8 @@ public class InstanceEditWindow extends Window {
}
ImGui.endTabItem();
}
//TODO drag-and-drop mods
if (instance.isFabric() && ImGui.beginTabItem("Mods")) {
lastTabWasMods = true;
if (!Files.exists(path.resolve("mods"))) {
try {
Files.createDirectories(path.resolve("mods"));
@ -261,16 +253,12 @@ public class InstanceEditWindow extends Window {
ImGui.text("Authentication");
boolean update = ImGui.inputText("Username", gitUsername);
update |= ImGui.inputText("Password", gitPassword, ImGuiInputTextFlags.Password);
ImGui.text("Commits");
if (update) {
if (!Inceptum.CONFIG.git.containsKey(name))
Inceptum.CONFIG.git.put(name, new Config.GitConfig());
Config.GitConfig config = Inceptum.CONFIG.git.get(name);
if (!Inceptum.CONFIG.git.instanceAuths.containsKey(name))
Inceptum.CONFIG.git.instanceAuths.put(name, new Config.GitConfig.GitAuth());
Config.GitConfig.GitAuth config = Inceptum.CONFIG.git.instanceAuths.get(name);
config.username = gitUsername.get();
config.password = gitPassword.get();
config.sign = gitSign.get();
config.authorName = gitAuthorName.get();
config.authorMail = gitAuthorMail.get();
Inceptum.saveConfig();
}
ImGui.endTabItem();
@ -280,20 +268,7 @@ public class InstanceEditWindow extends Window {
}
private void delete(ModsDirScanner.IWModDescription md) throws IOException {
Utils.deleteRecursive(md.path());
if (md.imod().isPresent() && Files.exists(md.imod().get())) Files.delete(md.imod().get());
if (md.mod().isPresent()) {
for (String dependency : md.mod().get().dependencies) {
Path dep = path.resolve("mods").resolve(dependency);
ModsDirScanner.IWModDescription dmd = mds.get(dep);
if (dmd.mod().isPresent()) {
dmd.mod().get().dependencies.remove(md.path().getFileName().toString());
if (dmd.mod().get().dependencies.isEmpty()) delete(dmd);
else if (dmd.imod().isPresent())
Utils.writeObject(dmd.imod().get(), dmd.mod().get());
}
}
}
ModManager.delete(md, path.resolve("mods"), mds);
}
private void save() {
@ -307,14 +282,13 @@ public class InstanceEditWindow extends Window {
@Override
public void close() {
super.close();
mds.close();
if (reDownload) {
try {
//TODO show progress
Steps.reDownload(path);
} catch (IOException e) {
Inceptum.showError("Could not re-download data", e);
}
InceptumGui.open(new ReDownloadWatcherWindow(path));
}
}
@Override
public int getFlags() {
return lastTabWasMods ? 0 : super.getFlags();
}
}

View File

@ -44,7 +44,16 @@ public class MainWindow extends Window {
Utils.clearDirectory(Inceptum.LIBRARIES_DIR, path -> !path.startsWith(Inceptum.LIBRARIES_DIR.resolve("io/gitlab/jfronny")));
Utils.clearDirectory(Inceptum.NATIVES_DIR, path -> !path.endsWith("forceload"));
Utils.clearDirectory(Inceptum.CACHE_DIR);
Steps.reDownload();
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();
} catch (IOException e) {
Inceptum.showError("Could not execute refresh task", e);
}

View File

@ -0,0 +1,39 @@
package io.gitlab.jfronny.inceptum.windows;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.install.SetupStepInfo;
import io.gitlab.jfronny.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

@ -49,7 +49,7 @@ public class InstanceView {
if (runDisabled) ImGui.beginDisabled();
if (ImGui.button(path.getFileName().toString())) {
try {
Steps.reDownload(path);
Steps.reDownload(path, state -> {});
} catch (IOException e) {
e.printStackTrace();
}