Sevaral TODOs, instance creation works
This commit is contained in:
parent
1d25d36ac7
commit
1d48cb3f38
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
Binary file not shown.
|
@ -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>
|
Loading…
Reference in New Issue