Sevaral TODOs, instance creation works

This commit is contained in:
JFronny 2021-10-28 20:19:09 +02:00
parent 1d25d36ac7
commit 1d48cb3f38
No known key found for this signature in database
GPG Key ID: BEC5ACBBD4EE17E5
21 changed files with 321 additions and 209 deletions

View File

@ -1,5 +1,6 @@
package io.gitlab.jfronny.glaunch;
public class Config {
public boolean snapshots = false;
public boolean snapshots = false; //TODO allow configuring
public boolean darkTheme = false;
}

View File

@ -5,6 +5,7 @@ import com.google.gson.GsonBuilder;
import imgui.ImGui;
import imgui.ImGuiIO;
import imgui.flag.ImGuiConfigFlags;
import imgui.flag.ImGuiWindowFlags;
import imgui.gl3.ImGuiImplGl3;
import imgui.glfw.ImGuiImplGlfw;
import io.gitlab.jfronny.glaunch.gson.MinecraftArgumentDeserializer;
@ -13,6 +14,7 @@ import io.gitlab.jfronny.glaunch.model.MinecraftArgument;
import io.gitlab.jfronny.glaunch.model.Rules;
import io.gitlab.jfronny.glaunch.util.Utils;
import io.gitlab.jfronny.glaunch.windows.MainWindow;
import io.gitlab.jfronny.glaunch.windows.Window;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.lwjgl.glfw.*;
@ -22,6 +24,7 @@ import org.lwjgl.system.MemoryStack;
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;
@ -41,11 +44,12 @@ public class GLaunch {
.registerTypeAdapter(MinecraftArgument.class, new MinecraftArgumentDeserializer())
.registerTypeAdapter(Rules.class, new RulesDeserializer())
.create();
//TODO allow moving to .config or elsewhere
public static final Path CACHE_DIR = Path.of("run/cache");
public static final Path INSTANCE_DIR = Path.of("run/instances");
public static final Path ASSETS_DIR = Path.of("run/assets");
public static final Path LIBRARIES_DIR = Path.of("run/libraries");
private static final Path CONFIG_PATH = Path.of("glaunch2.json");
private static final Path CONFIG_PATH = Path.of("run/glaunch2.json");
public static Config CONFIG;
public static void main(String[] args) throws IOException {
@ -94,8 +98,11 @@ public class GLaunch {
protected void dispose() {
imGuiGl3.dispose();
imGuiGlfw.dispose();
disposeImGui();
disposeWindow();
ImGui.destroyContext();
Callbacks.glfwFreeCallbacks(handle);
GLFW.glfwDestroyWindow(handle);
GLFW.glfwTerminate();
Objects.requireNonNull(GLFW.glfwSetErrorCallback(null)).free();
}
/**
@ -133,17 +140,8 @@ public class GLaunch {
GLFW.glfwSwapInterval(GLFW.GLFW_TRUE);
//GLFW.glfwShowWindow(handle);
clearBuffer();
renderBuffer();
GLFW.glfwSetWindowSizeCallback(handle, new GLFWWindowSizeCallback() {
@Override
public void invoke(final long window, final int width, final int height) {
runFrame();
}
});
}
private void decideGlGlslVersions() {
@ -170,6 +168,12 @@ public class GLaunch {
io.addConfigFlags(ImGuiConfigFlags.ViewportsEnable);
//io.setConfigViewportsNoDecoration(false);
io.setConfigViewportsNoAutoMerge(true);
try (InputStream is = GLaunch.class.getClassLoader().getResourceAsStream("font.ttf")) {
assert is != null;
io.setFontDefault(io.getFonts().addFontFromMemoryTTF(is.readAllBytes(), 16f));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
@ -177,92 +181,43 @@ public class GLaunch {
*/
protected void run() {
while (!GLFW.glfwWindowShouldClose(handle)) {
runFrame();
}
}
/**
* Method used to run the next frame.
*/
protected void runFrame() {
startFrame();
process();
endFrame();
}
public void process() {
if (GLaunch.WINDOWS.isEmpty()) close();
else {
for (Window window : GLaunch.WINDOWS.toArray(new Window[0])) {
if (window.isNew()) window.preFirstDraw();
ImGui.begin(window.getName());
window.draw();
ImGui.end();
//frame
clearBuffer();
imGuiGlfw.newFrame();
if (CONFIG.darkTheme) ImGui.styleColorsDark();
else ImGui.styleColorsLight();
ImGui.newFrame();
//render
if (GLaunch.WINDOWS.isEmpty()) GLFW.glfwSetWindowShouldClose(handle, true); //TODO fix hs_error_pid
else {
for (Window window : GLaunch.WINDOWS.toArray(new Window[0])) {
if (window.isNew()) window.preFirstDraw();
ImGui.begin(window.getName(), ImGuiWindowFlags.MenuBar);
window.draw();
ImGui.end();
}
}
//end frame
ImGui.render();
imGuiGl3.renderDrawData(ImGui.getDrawData());
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
final long backupWindowPtr = GLFW.glfwGetCurrentContext();
ImGui.updatePlatformWindows();
ImGui.renderPlatformWindowsDefault();
GLFW.glfwMakeContextCurrent(backupWindowPtr);
}
renderBuffer();
}
}
/**
* Method used to clear the OpenGL buffer.
*/
private void clearBuffer() {
GL32.glClear(GL32.GL_COLOR_BUFFER_BIT | GL32.GL_DEPTH_BUFFER_BIT);
}
/**
* Method called at the beginning of the main cycle.
* It clears OpenGL buffer and starts an ImGui frame.
*/
protected void startFrame() {
clearBuffer();
imGuiGlfw.newFrame();
ImGui.newFrame();
}
/**
* Method called in the end of the main cycle.
* It renders ImGui and swaps GLFW buffers to show an updated frame.
*/
protected void endFrame() {
ImGui.render();
imGuiGl3.renderDrawData(ImGui.getDrawData());
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
final long backupWindowPtr = GLFW.glfwGetCurrentContext();
ImGui.updatePlatformWindows();
ImGui.renderPlatformWindowsDefault();
GLFW.glfwMakeContextCurrent(backupWindowPtr);
}
renderBuffer();
}
/**
* Method to render the OpenGL buffer and poll window events.
*/
private void renderBuffer() {
GLFW.glfwSwapBuffers(handle);
GLFW.glfwPollEvents();
}
/**
* Method to destroy Dear ImGui context.
*/
protected void disposeImGui() {
ImGui.destroyContext();
}
/**
* Method to destroy GLFW window.
*/
protected void disposeWindow() {
Callbacks.glfwFreeCallbacks(handle);
GLFW.glfwDestroyWindow(handle);
GLFW.glfwTerminate();
Objects.requireNonNull(GLFW.glfwSetErrorCallback(null)).free();
}
public void close() {
GLFW.glfwSetWindowShouldClose(handle, true);
}
}

View File

@ -21,9 +21,15 @@ public class MinecraftArgumentDeserializer implements JsonDeserializer<Minecraft
Rules r = context.deserialize(jo.get("rules"), Rules.class);
if (!r.allow()) return new MinecraftArgument(Set.of());
Set<String> sel = new LinkedHashSet<>();
for (JsonElement value : jo.get("value").getAsJsonArray()) {
sel.add(value.getAsString());
JsonElement value = jo.get("value");
if (value.isJsonArray()) {
for (JsonElement val : value.getAsJsonArray()) {
sel.add(val.getAsString());
}
}
else if (value.isJsonPrimitive())
sel.add(value.getAsString());
else throw new JsonParseException("Unexpected value type");
return new MinecraftArgument(Set.copyOf(sel));
}
else throw new JsonParseException("Not a valid minecraft argument");

View File

@ -12,27 +12,32 @@ public class RulesDeserializer implements JsonDeserializer<Rules> {
boolean valid = true;
for (JsonElement rule : json.getAsJsonArray()) {
JsonObject ro = rule.getAsJsonObject();
if (!ro.get("action").getAsJsonPrimitive().getAsString().equals("allow"))
throw new JsonParseException("Unexpected action in argument");
String actionType = ro.get("action").getAsJsonPrimitive().getAsString();
if (!actionType.equals("allow") && !actionType.equals("disallow")) {
throw new JsonParseException("Unexpected action in argument: " + actionType);
}
boolean matched = true;
if (ro.has("features")) { //TODO support has_custom_resolution
valid = false;
continue;
matched = false;
}
if (ro.has("os")) {
JsonObject osObject = ro.get("os").getAsJsonObject();
if (osObject.has("name")) {
if (!Utils.getOs().equals(osObject.get("name").getAsString())) {
valid = false;
break;
if (!Utils.OS.equals(osObject.get("name").getAsString())) {
matched = false;
}
}
if (osObject.has("version")) {
if (!System.getProperty("os.version").matches(osObject.get("version").getAsString())) {
valid = false;
break;
matched = false;
}
}
}
if (actionType.equals("disallow")) matched = !matched;
if (!matched) {
valid = false;
break;
}
}
return new Rules(valid);
}

View File

@ -2,14 +2,16 @@ package io.gitlab.jfronny.glaunch.install;
import io.gitlab.jfronny.glaunch.install.steps.*;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class Steps {
public static Set<Step> STEPS = Set.of(
public static Set<Step> STEPS = new LinkedHashSet<>(List.of(
new SetupDirsStep(),
new DownloadClientStep(),
new DownloadAssetsStep(),
new DownloadLibrariesStep(),
new WriteMetadataStep()
new WriteMetadataStep())
);
}

View File

@ -14,12 +14,14 @@ import java.util.Map;
public class DownloadAssetsStep implements Step {
@Override
public void execute(SetupStepInfo info) throws IOException {
//TODO feedback
Path o = GLaunch.ASSETS_DIR.resolve("objects");
for (Map.Entry<String, AssetIndex.Asset> entry : McApi.getAssetIndex(info.version()).objects.entrySet()) {
Path fPath = o.resolve(entry.getValue().hash.substring(0, 2));
if (!Files.exists(fPath)) Files.createDirectories(fPath);
McApi.downloadAsset(entry.getValue(), fPath.resolve(entry.getValue().hash));
fPath = fPath.resolve(entry.getValue().hash);
if (Files.exists(fPath)) return;
GLaunch.LOGGER.info("Downloading asset: " + entry.getKey());
McApi.downloadAsset(entry.getValue(), fPath);
}
}
}

View File

@ -7,11 +7,16 @@ import io.gitlab.jfronny.glaunch.model.VersionInfo;
import io.gitlab.jfronny.glaunch.util.Utils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class DownloadClientStep implements Step {
@Override
public void execute(SetupStepInfo info) throws IOException {
VersionInfo.Downloads.Download client = info.version().downloads.client;
Utils.downloadFile(client.url, client.sha1, GLaunch.LIBRARIES_DIR.resolve(info.version().id + ".jar"));
GLaunch.LOGGER.info("Downloading client");
Path parentPath = GLaunch.LIBRARIES_DIR.resolve("net/minecraft/minecraft");
if (!Files.exists(parentPath)) Files.createDirectories(parentPath);
Utils.downloadFile(client.url, client.sha1, parentPath.resolve(info.version().id + ".jar"));
}
}

View File

@ -3,34 +3,35 @@ package io.gitlab.jfronny.glaunch.install.steps;
import io.gitlab.jfronny.glaunch.GLaunch;
import io.gitlab.jfronny.glaunch.install.SetupStepInfo;
import io.gitlab.jfronny.glaunch.install.Step;
import io.gitlab.jfronny.glaunch.model.Rules;
import io.gitlab.jfronny.glaunch.model.VersionInfo;
import io.gitlab.jfronny.glaunch.util.Utils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class DownloadLibrariesStep implements Step {
@Override
public void execute(SetupStepInfo info) throws IOException {
//TODO feedback
mainLoop: for (VersionInfo.Library library : info.version().libraries) {
for (Rules rule : library.rules) {
if (!rule.allow()) continue mainLoop;
for (VersionInfo.Library library : info.version().libraries) {
if (library.rules != null && !library.rules.allow()) continue;
if (library.downloads.classifiers != null && library.natives != null && library.natives.containsKey(Utils.OS)) {
downloadLib(library.downloads.classifiers.get(library.natives.get(Utils.OS)));
}
if (library.classifiers != null) {
downloadLib(switch (Utils.getOs()) {
case "osx" -> library.classifiers.nativesMacos;
case "windows" -> library.classifiers.nativesWindows;
case "linux" -> library.classifiers.nativesLinux;
default -> throw new RuntimeException("Not a valid OS");
});
if (library.downloads.artifact == null) {
GLaunch.LOGGER.info("Null library artifact @ " + library.name);
continue;
}
downloadLib(library.artifact);
downloadLib(library.downloads.artifact);
}
}
private void downloadLib(VersionInfo.Library.Artifact artifact) throws IOException {
private void downloadLib(VersionInfo.Library.Downloads.Artifact artifact) throws IOException {
Path path = GLaunch.LIBRARIES_DIR.resolve(artifact.path);
if (Files.exists(path)) return;
//TODO allow maven-like download for fabric
Utils.downloadFile(artifact.url, artifact.sha1, GLaunch.LIBRARIES_DIR.resolve(artifact.path));
GLaunch.LOGGER.info("Downloading library: " + artifact.path);
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
Utils.downloadFile(artifact.url, artifact.sha1, path);
}
}

View File

@ -11,6 +11,7 @@ import java.nio.file.Path;
public class SetupDirsStep implements Step {
@Override
public void execute(SetupStepInfo info) throws IOException {
GLaunch.LOGGER.info("Setting up instance dirs");
Path iDir = GLaunch.INSTANCE_DIR.resolve(info.name());
if (!Files.exists(iDir)) {
Files.createDirectories(iDir);

View File

@ -12,6 +12,7 @@ import java.nio.file.Path;
public class WriteMetadataStep implements Step {
@Override
public void execute(SetupStepInfo info) throws IOException {
GLaunch.LOGGER.info("Writing metadata");
Path metaDir = GLaunch.INSTANCE_DIR.resolve(info.name()).resolve("instance.json");
InstanceMeta meta = new InstanceMeta();
meta.loaderType = info.loaderType();

View File

@ -1,8 +1,7 @@
package io.gitlab.jfronny.glaunch.model;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.Map;
public class VersionInfo {
public Arguments arguments;
@ -51,24 +50,21 @@ public class VersionInfo {
}
public static class Library {
public Artifact artifact;
public Downloads downloads;
public String name;
public Set<Rules> rules = new LinkedHashSet<>();
public Classifiers classifiers;
public Map<String, String> natives;
public Rules rules;
public static class Artifact {
public String path;
public String sha1;
public int size;
public String url;
}
public static class Downloads {
public Artifact artifact;
public Map<String, Artifact> classifiers;
public static class Classifiers {
public Artifact javadoc;
public Artifact nativesLinux;
public Artifact nativesMacos;
public Artifact nativesWindows;
public Artifact sources;
public static class Artifact {
public String path;
public String sha1;
public int size;
public String url;
}
}
}
@ -77,7 +73,7 @@ public class VersionInfo {
public static class Client {
public String argument;
public Library.Artifact file;
public Library.Downloads.Artifact file;
public String type;
}
}

View File

@ -0,0 +1,52 @@
package io.gitlab.jfronny.glaunch.util;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Core;
import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
import org.apache.logging.log4j.core.config.plugins.PluginElement;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.util.StringBuilderFormattable;
import java.time.Instant;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Plugin(name = "MapAppender", category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE)
public class MapAppender extends AbstractAppender {
public static final ConcurrentMap<String, LogEvent> EVENT_MAP = new ConcurrentHashMap<>();
public static final Set<String> LOG = new LinkedHashSet<>();
protected MapAppender(String name, Filter filter) {
//super(name, filter, null);
super(name, filter, null, false, null);
}
@PluginFactory
public static MapAppender createAppender(
@PluginAttribute("name") String name,
@PluginElement("Filter") Filter filter) {
return new MapAppender(name, filter);
}
@Override
public void append(LogEvent event) {
EVENT_MAP.put(Instant.now().toString(), event);
StringBuilder msg = new StringBuilder(event.getLevel().name())
.append(" | ")
.append(Instant.now().toString())
.append(" | [")
.append(event.getThreadName())
.append("] ")
.append(event.getSource().getClassName())
.append(" - ");
if (event.getMessage() instanceof StringBuilderFormattable sbf) sbf.formatTo(msg);
else msg.append(event.getMessage().getFormattedMessage());
LOG.add(msg.toString());
}
}

View File

@ -5,14 +5,30 @@ import io.gitlab.jfronny.glaunch.GLaunch;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.Locale;
import java.util.regex.Pattern;
public class Utils {
public static final Pattern VALID_FILENAME = Pattern.compile("[a-zA-Z0-9_\\-.][a-zA-Z0-9 _\\-.]*[a-zA-Z0-9_\\-.]");
public static final String OS;
static {
String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ROOT);
if ((os.contains("mac")) || (os.contains("darwin"))) {
OS = "osx";
} else if (os.contains("win")) {
OS = "windows";
} else if (os.contains("nux")) {
OS = "linux";
} else {
throw new RuntimeException("Unrecognized OS");
}
}
public static String hash(byte[] data) {
Formatter formatter = new Formatter();
try {
@ -24,19 +40,6 @@ public class Utils {
return formatter.toString();
}
public static String getOs() {
String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ROOT);
if ((os.contains("mac")) || (os.contains("darwin"))) {
return "osx";
} else if (os.contains("win")) {
return "windows";
} else if (os.contains("nux")) {
return "linux";
} else {
throw new RuntimeException("Unrecognized OS");
}
}
public static byte[] downloadData(String url) throws IOException {
try (InputStream is = new URL(url).openStream()) {
return is.readAllBytes();
@ -95,7 +98,7 @@ public class Utils {
}
public static <T> void writeObject(Path file, T object) throws IOException {
try (BufferedWriter bw = Files.newBufferedWriter(file)) {
try (BufferedWriter bw = Files.newBufferedWriter(file, StandardOpenOption.CREATE)) {
GLaunch.GSON.toJson(object, bw);
}
}
@ -119,4 +122,24 @@ public class Utils {
public static void downloadFile(String url, String sha1, Path path) throws IOException {
Files.write(path, downloadData(url, sha1));
}
public static void deleteRecursive(Path path) throws IOException {
Files.walkFileTree(path, new SimpleFileVisitor<>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
FileVisitResult fv = super.visitFile(file, attrs);
if (fv != FileVisitResult.CONTINUE) return fv;
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
FileVisitResult fv = super.postVisitDirectory(dir, exc);
if (fv != FileVisitResult.CONTINUE) return fv;
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
});
}
}

View File

@ -1,7 +1,6 @@
package io.gitlab.jfronny.glaunch.windows;
import imgui.ImGui;
import io.gitlab.jfronny.glaunch.Window;
public class AlertWindow extends Window {
private final String message;

View File

@ -0,0 +1,15 @@
package io.gitlab.jfronny.glaunch.windows;
import imgui.ImGui;
import io.gitlab.jfronny.glaunch.util.MapAppender;
public class LogWindow extends Window {
public LogWindow() {
super("Log");
}
@Override
public void draw() {
MapAppender.LOG.forEach(ImGui::textUnformatted);
}
}

View File

@ -2,7 +2,6 @@ package io.gitlab.jfronny.glaunch.windows;
import imgui.ImGui;
import io.gitlab.jfronny.glaunch.GLaunch;
import io.gitlab.jfronny.glaunch.Window;
public class MainWindow extends Window {
public MainWindow() {
@ -11,10 +10,15 @@ public class MainWindow extends Window {
@Override
public void draw() {
if (ImGui.button("Close"))
close();
if (ImGui.button("New")) {
GLaunch.open(new NewInstanceWindow());
}
if (ImGui.button("Close")) close();
ImGui.sameLine();
if (ImGui.button("New")) GLaunch.open(new NewInstanceWindow());
ImGui.sameLine();
if (ImGui.button("Style")) GLaunch.open(new StyleWindow());
if (ImGui.button("Log")) GLaunch.open(new LogWindow()); //TODO remember windows
//ImGui.showAboutWindow();
//ImGui.showUserGuide();
//ImGui.showMetricsWindow();
//ImGui.showStyleEditor();
}
}

View File

@ -1,88 +1,111 @@
package io.gitlab.jfronny.glaunch.windows;
import imgui.ImGui;
import imgui.type.ImBoolean;
import imgui.type.ImInt;
import imgui.type.ImString;
import io.gitlab.jfronny.glaunch.GLaunch;
import io.gitlab.jfronny.glaunch.Window;
import io.gitlab.jfronny.glaunch.install.SetupStepInfo;
import io.gitlab.jfronny.glaunch.install.Step;
import io.gitlab.jfronny.glaunch.install.Steps;
import io.gitlab.jfronny.glaunch.model.VersionsList;
import io.gitlab.jfronny.glaunch.model.VersionsListInfo;
import io.gitlab.jfronny.glaunch.util.Utils;
import io.gitlab.jfronny.glaunch.util.mojang.McApi;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
public class NewInstanceWindow extends Window {
VersionsList manifest = McApi.getVersions();
VersionsListInfo selected = null;
LoaderType loaderType = null;
State state = State.Version;
String name = "";
VersionsListInfo selected;
State state = State.Configure;
ImInt version = new ImInt(0); //TODO select latest stable
ImString name = new ImString("", 128);
ImBoolean snapshots = new ImBoolean(GLaunch.CONFIG.snapshots);
ImBoolean fabric = new ImBoolean(true);
public NewInstanceWindow() {
super("New Instance");
}
@Override
public void preFirstDraw() {
ImGui.setNextWindowSize(200, 800);
selected = getVersions(false).get(0);
if (GLaunch.CONFIG.snapshots)
version.set(manifest.versions.indexOf(selected));
name.set(getDefaultName(selected, fabric.get()));
}
@Override
public void draw() {
if (ImGui.button("Cancel")) close();
if (ImGui.button("Cancel")) close(); //TODO use actual close button
switch (state) {
case Version -> {
ImGui.text("Select a version");
GLaunch.CONFIG.snapshots = ImGui.checkbox("Show snapshots", GLaunch.CONFIG.snapshots);
if (ImGui.checkbox("Ae", true)) { //TODO fix
GLaunch.LOGGER.info("Ao");
case Configure -> {
if (ImGui.checkbox("Show snapshots", snapshots)) {
boolean prev = GLaunch.CONFIG.snapshots;
GLaunch.CONFIG.snapshots = snapshots.get();
//fix version index
int i = getVersions(GLaunch.CONFIG.snapshots).indexOf(getVersions(prev).get(version.get()));
if (i == -1) version.set(0);
else version.set(i);
}
for (VersionsListInfo version : manifest.versions) {
if (!version.type.equals("release") && !GLaunch.CONFIG.snapshots) continue;
if (ImGui.button(version.id)) {
selected = version;
state = State.Loader;
break;
}
List<VersionsListInfo> vil = getVersions(GLaunch.CONFIG.snapshots);
if (ImGui.combo("Version", version, vil.stream().map(info -> info.id).toArray(String[]::new))) {
VersionsListInfo prev = selected;
selected = vil.get(version.get());
if (getDefaultName(prev, fabric.get()).equals(name.get()))
name.set(getDefaultName(selected, fabric.get())); //TODO "<ver> (1)" etc if exists
}
}
case Loader -> {
ImGui.text("Select a mod loader"); //TODO implement fabric support
for (LoaderType value : LoaderType.values()) {
if (ImGui.button(value.name())) {
state = State.Name;
}
if (ImGui.checkbox("Fabric support", fabric)) {
if (getDefaultName(selected, !fabric.get()).equals(name.get()))
name.set(getDefaultName(selected, fabric.get()));
}
}
case Name -> {
ImString is = new ImString(name);
ImGui.text("Select a name");
ImGui.inputText("", is);
name = is.get();
if (ImGui.button("OK"))
//TODO forge
//TODO implement fabric support
ImGui.inputTextWithHint("Name", "Select a name", name);
if (!Utils.VALID_FILENAME.matcher(name.get()).matches())
ImGui.text("Invalid name");
else if (Files.exists(GLaunch.INSTANCE_DIR.resolve(name.get())))
ImGui.text("Already exists");
else if (ImGui.button("OK"))
state = State.Installing;
}
case Installing -> {
ImGui.text("Installing...");
if (Files.exists(GLaunch.INSTANCE_DIR.resolve(name.get()))) {
ImGui.text("Already exists");
}
ImGui.text("Installing..."); //TODO update UI during process
try {
SetupStepInfo stepInfo = new SetupStepInfo(McApi.getVersionInfo(selected), loaderType, name);
SetupStepInfo stepInfo = new SetupStepInfo(McApi.getVersionInfo(selected), fabric.get() ? LoaderType.Fabric : LoaderType.None, name.get());
for (Step step : Steps.STEPS) {
step.execute(stepInfo);
}
} catch (IOException e) {
GLaunch.open(new AlertWindow("Successfully installed!"));
close();
} catch (Throwable e) {
GLaunch.LOGGER.error("Could not initialize instance", e);
GLaunch.open(new AlertWindow("Could not initialize instance, look at the log for details"));
close();
try {
Utils.deleteRecursive(GLaunch.INSTANCE_DIR.resolve(name.get()));
} catch (IOException ex) {
GLaunch.LOGGER.error("Could not delete instance dir", e);
}
}
}
}
}
private List<VersionsListInfo> getVersions(boolean snapshots) {
ArrayList<VersionsListInfo> res = new ArrayList<>(manifest.versions);
res.removeIf(info -> !snapshots && !info.type.equals("release"));
return res;
}
private String getDefaultName(VersionsListInfo info, boolean fabric) {
return fabric ? "Fabric " + info.id : info.id;
}
enum State {
Version,
Loader,
Name,
Configure,
Installing
}

View File

@ -0,0 +1,17 @@
package io.gitlab.jfronny.glaunch.windows;
import imgui.ImGui;
//TODO remove
public class StyleWindow extends Window {
public StyleWindow() {
super("Styles");
}
@Override
public void draw() {
if (ImGui.button("Close")) close();
ImGui.showAboutWindow();
ImGui.showDemoWindow();
}
}

View File

@ -1,4 +1,6 @@
package io.gitlab.jfronny.glaunch;
package io.gitlab.jfronny.glaunch.windows;
import io.gitlab.jfronny.glaunch.GLaunch;
public abstract class Window {
private final String name;

BIN
src/main/resources/font.ttf Normal file

Binary file not shown.

View File

@ -1,18 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config">
<Properties>
<Property name="basePath">../Log4j2Example/logs</Property>
</Properties>
<Configuration xmlns="http://logging.apache.org/log4j/2.0/config" packages="io.gitlab.jfronny.glaunch.util">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%-5p | %d{yyyy-MM-dd HH:mm:ss} | [%t] %C{2} (%F:%L) - %m%n" />
</Console>
<MapAppender name="MapAppender" />
<File name="FILE" fileName="run/logs/latest.log">
<PatternLayout pattern="%d{yyyy-mm-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
</File>
</Appenders>
<Loggers>
<Logger name="com.jcg" level="debug" />
<Root level="info">
<AppenderRef ref="STDOUT" />
<AppenderRef ref="FILE" />
<AppenderRef ref="MapAppender" />
</Root>
</Loggers>
</Configuration>