Major refactors

This commit is contained in:
Johannes Frohnmeyer 2022-09-04 21:21:24 +02:00
parent 547889ce7f
commit d777b9f39d
Signed by: Johannes
GPG Key ID: E76429612C2929F4
194 changed files with 1999 additions and 1968 deletions

View File

@ -16,19 +16,19 @@ build_test:
script:
- TIMESTAMP=$(date +%s)
- gradle --build-cache build publish -Pflavor=nogui -Ppublic -Ptimestamp=$TIMESTAMP
- gradle --build-cache build publish -Pflavor=fat -Ppublic -Ptimestamp=$TIMESTAMP
- gradle --build-cache build publish -Pflavor=windows -Ppublic -Ptimestamp=$TIMESTAMP
- gradle --build-cache build publish -Pflavor=linux -Ppublic -Ptimestamp=$TIMESTAMP
- gradle --build-cache build publish -Pflavor=macos -Ppublic -Ptimestamp=$TIMESTAMP
- gradle --build-cache build :Inceptum:publish -Pflavor=fat -Ppublic -Ptimestamp=$TIMESTAMP
- gradle --build-cache build :Inceptum:publish -Pflavor=windows -Ppublic -Ptimestamp=$TIMESTAMP
- gradle --build-cache build :Inceptum:publish -Pflavor=linux -Ppublic -Ptimestamp=$TIMESTAMP
- gradle --build-cache build :Inceptum:publish -Pflavor=macos -Ppublic -Ptimestamp=$TIMESTAMP
- gradle --build-cache :exportMetadata -Ppublic -Ptimestamp=$TIMESTAMP
- mkdir -p build/libs
- cp launcher/build/libs/* build/libs/
- cp launcher-shadowed/build/libs/* build/libs/
- cp wrapper/build/libs/* build/libs/
- cp launcher/build/libs/*-*-*-*.jar ./
- cp launcher-shadowed/build/libs/*-*-*-*.jar ./
- cp wrapper/build/libs/*.exe wrapper.exe
- cp wrapper/build/libs/*-all.jar wrapper.jar
- for f in *-*-*.jar; do mv "$f" "latest-${f##*-}";done
- mv latest-fat.jar latest.jar
- unzip -p latest.jar version.json > version.json
artifacts:
paths:
- build/libs
@ -76,10 +76,10 @@ deploy:
stage: deploy
script:
- gradle --build-cache build publish -Pflavor=nogui -Ppublic -Prelease
- gradle --build-cache build publish -Pflavor=fat -Ppublic -Prelease
- gradle --build-cache build publish -Pflavor=windows -Ppublic -Prelease
- gradle --build-cache build publish -Pflavor=linux -Ppublic -Prelease
- gradle --build-cache build publish -Pflavor=macos -Ppublic -Prelease
- gradle --build-cache build :Inceptum:publish -Pflavor=fat -Ppublic -Prelease
- gradle --build-cache build :Inceptum:publish -Pflavor=windows -Ppublic -Prelease
- gradle --build-cache build :Inceptum:publish -Pflavor=linux -Ppublic -Prelease
- gradle --build-cache build :Inceptum:publish -Pflavor=macos -Ppublic -Prelease
pages:
image: python:3.8-buster

View File

@ -1,10 +1,13 @@
# Inceptum Launcher
An advanced FOSS Launcher for Minecraft written in Java
For documentation on how to use or install Inceptum, please head to the [wiki](https://jfmods.gitlab.io/inceptum)
## Licenses
Inceptum utilizes code/libraries/assets from:
- [ATLauncher](https://github.com/ATLauncher/ATLauncher): Microsoft authentication
- [MultiMC](https://github.com/MultiMC/Launcher): Used as a reference for some implementations
- [imgui-java](https://github.com/SpaiR/imgui-java): The library used for UI

View File

@ -1,5 +1,5 @@
import org.gradle.internal.os.OperatingSystem
import org.ajoberstar.grgit.Grgit
import org.gradle.internal.os.OperatingSystem
plugins {
id("org.ajoberstar.grgit") version "5.0.0" apply false
@ -18,22 +18,42 @@ if (File(".git").exists()) {
println("Building Inceptum $currentVer")
val timestamp: Long =
if (project.hasProperty("timestamp")) "${project.property("timestamp")}".toLong() else (System.currentTimeMillis() / 1000L)
allprojects {
version = currentVer + if (project.hasProperty("release")) "" else "-" + (if (project.hasProperty("timestamp")) project.property("timestamp") else "${System.currentTimeMillis() / 1000L}")
version = currentVer + if (project.hasProperty("release")) "" else "-$timestamp"
group = "io.gitlab.jfronny.inceptum"
}
val lwjglVersion by extra("3.3.1")
val imguiVersion by extra("1.86.4")
val logbackVersion by extra("1.3.0-alpha15")
val jfCommonsVersion by extra("2022.7.4+11-13-3")
val jfCommonsVersion by extra("2022.9.4+14-8-34")
val jgitVersion by extra("6.2.0.202206071550-r")
val flavorProp: String by extra(if (project.hasProperty("flavor")) "${project.property("flavor")}" else "custom")
val flavor: String by extra(if (flavorProp != "custom") flavorProp else when (OperatingSystem.current()) {
val flavor: String by extra(
if (flavorProp != "custom") flavorProp else when (OperatingSystem.current()) {
OperatingSystem.WINDOWS -> "windows"
OperatingSystem.LINUX -> "linux"
OperatingSystem.MAC_OS -> "macos"
else -> throw IllegalStateException()
})
}
)
val isPublic by extra(project.hasProperty("public"))
val isRelease by extra(project.hasProperty("release"))
val isRelease by extra(project.hasProperty("release"))
tasks.register("exportMetadata") {
doLast {
projectDir.resolve("version.json").writeText(
"""
{
"version": "$version",
"isPublic": $isPublic,
"isRelease": $isRelease,
"jvm": ${project(":common").extra["javaVersion"]}
}
""".trimIndent()
)
}
}

12
buildSrc/build.gradle.kts Normal file
View File

@ -0,0 +1,12 @@
plugins {
`kotlin-dsl`
}
repositories {
gradlePluginPortal()
}
dependencies {
implementation("gradle.plugin.com.github.johnrengelman:shadow:7.1.2")
implementation("de.undercouch:gradle-download-task:5.1.2")
}

View File

@ -0,0 +1 @@
rootProject.name="inceptum-conventions"

View File

@ -0,0 +1,12 @@
plugins {
application
id("inceptum.java-conventions")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
}
}
}

View File

@ -0,0 +1,56 @@
import java.io.FileOutputStream
import de.undercouch.gradle.tasks.download.Download
plugins {
application
id("inceptum.java-conventions")
id("com.github.johnrengelman.shadow")
id("de.undercouch.download")
}
abstract class FileOutput : DefaultTask() {
@get:OutputFile
abstract var output: File
}
val bootstrapVersion = "0.3.2"
val bootstrapArch = "i686"
val downloadBootstrap by tasks.registering(Download::class) {
src("https://maven.fabricmc.net/net/fabricmc/fabric-installer-native-bootstrap/windows-${bootstrapArch}/${bootstrapVersion}/windows-${bootstrapArch}-${bootstrapVersion}.exe")
dest(project.buildDir)
}
val nativeExe by tasks.registering(FileOutput::class) {
dependsOn(downloadBootstrap)
dependsOn(tasks.shadowJar)
output = file("$buildDir/libs/${project.name}-${project.version}.exe")
outputs.upToDateWhen { false }
doFirst {
output.delete()
}
doLast {
output.createNewFile()
FileOutputStream(output).use { w ->
w.write(downloadBootstrap.get().outputFiles.first().readBytes())
w.write(tasks.shadowJar.get().archiveFile.get().asFile.readBytes())
}
}
}
if (rootProject.extra["flavor"] == "windows") {
tasks.build.get().dependsOn(nativeExe)
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks.shadowJar) {
builtBy(tasks.shadowJar)
}
}
}
}

View File

@ -0,0 +1,35 @@
plugins {
`java-library`
`maven-publish`
}
repositories {
mavenCentral()
maven {
setUrl("https://gitlab.com/api/v4/projects/35745143/packages/maven")
}
}
dependencies {
compileOnly("org.jetbrains:annotations:23.0.0")
}
publishing {
repositories {
if (rootProject.extra["isPublic"] == true) {
maven {
url = uri("https://gitlab.com/api/v4/projects/30862253/packages/maven")
name = "gitlab"
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv()["CI_JOB_TOKEN"]
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
mavenLocal()
}
}

View File

@ -0,0 +1,11 @@
plugins {
id("inceptum.java-conventions")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
}
}
}

1
common/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
src/main/java/io/gitlab/jfronny/inceptum/common/BuildMetadata.java

View File

@ -1,12 +1,5 @@
plugins {
`java-library`
}
repositories {
mavenCentral()
maven {
setUrl("https://gitlab.com/api/v4/projects/35745143/packages/maven")
}
id("inceptum.library-conventions")
}
dependencies {
@ -14,17 +7,20 @@ dependencies {
api("io.gitlab.jfronny:commons-gson:${rootProject.extra["jfCommonsVersion"]}")
implementation("io.gitlab.jfronny:commons-slf4j:${rootProject.extra["jfCommonsVersion"]}")
implementation("ch.qos.logback:logback-classic:${rootProject.extra["logbackVersion"]}")
compileOnly("org.jetbrains:annotations:23.0.0")
}
tasks.processResources {
filesMatching("version.json") {
expand(
"version" to project.version,
"flavor" to rootProject.extra["flavorProp"],
"isPublic" to rootProject.extra["isPublic"],
"isRelease" to rootProject.extra["isRelease"],
"jvm" to project.java.targetCompatibility
)
val javaVersion by extra(project.java.targetCompatibility)
projectDir.resolve("src/main/java/io/gitlab/jfronny/inceptum/common/BuildMetadata.java").writeText(
"""
package io.gitlab.jfronny.inceptum.common;
import io.gitlab.jfronny.commons.ComparableVersion;
public class BuildMetadata {
public static final ComparableVersion VERSION = new ComparableVersion("$version");
public static final boolean IS_PUBLIC = ${rootProject.extra["isPublic"]};
public static final boolean IS_RELEASE = ${rootProject.extra["isRelease"]};
public static final int VM_VERSION = $javaVersion;
}
}
""".trimIndent())

View File

@ -1,6 +1,7 @@
package io.gitlab.jfronny.inceptum.util;
package io.gitlab.jfronny.inceptum.common;
import io.gitlab.jfronny.inceptum.model.inceptum.Config;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.common.model.inceptum.Config;
import java.io.IOException;
import java.nio.file.Files;
@ -11,17 +12,17 @@ public class ConfigHolder {
public static Config CONFIG;
public static void load() throws IOException {
if (!Files.exists(MetaHolder.CONFIG_PATH.getParent())) Files.createDirectories(MetaHolder.CONFIG_PATH.getParent());
if (!Files.exists(MetaHolder.CONFIG_PATH.getParent()))
Files.createDirectories(MetaHolder.CONFIG_PATH.getParent());
if (!Files.exists(MetaHolder.CONFIG_PATH)) {
Path gLaunch2 = MetaHolder.BASE_PATH.resolve("glaunch2.json");
if (Files.exists(gLaunch2)) {
Files.move(gLaunch2, MetaHolder.CONFIG_PATH);
}
else {
Utils.writeObject(MetaHolder.CONFIG_PATH, new Config());
} else {
JFiles.writeObject(MetaHolder.CONFIG_PATH, new Config());
}
}
CONFIG = Utils.loadObject(MetaHolder.CONFIG_PATH, Config.class);
CONFIG = JFiles.readObject(MetaHolder.CONFIG_PATH, Config.class);
boolean changed = false;
if (CONFIG.git == null) {
CONFIG.git = new Config.GitConfig();
@ -36,7 +37,7 @@ public class ConfigHolder {
public static void saveConfig() {
try {
Utils.writeObject(MetaHolder.CONFIG_PATH, CONFIG);
JFiles.writeObject(MetaHolder.CONFIG_PATH, CONFIG);
} catch (IOException e) {
Utils.LOGGER.error("Could not save config", e);
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.util;
package io.gitlab.jfronny.inceptum.common;
import io.gitlab.jfronny.commons.HttpUtils;
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
@ -7,7 +7,7 @@ import java.io.IOException;
public class InceptumEnvironmentInitializer {
public static void initialize() throws IOException {
HttpUtils.setUserAgent("jfmods/inceptum/" + MetaHolder.VERSION.version.toString());
HttpUtils.setUserAgent("jfmods/inceptum/" + BuildMetadata.VERSION);
GsonHolder.register();
ConfigHolder.load();
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.util;
package io.gitlab.jfronny.inceptum.common;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.AppenderBase;
@ -16,6 +16,7 @@ public class MapAppender extends AppenderBase<ILoggingEvent> {
@Override
protected void append(ILoggingEvent event) {
EVENT_MAP.put(Instant.now().toString(), event);
LOG.add(event.getLevel().toString() +
" | " +
Instant.now().toString() +

View File

@ -1,34 +1,26 @@
package io.gitlab.jfronny.inceptum.util;
package io.gitlab.jfronny.inceptum.common;
import io.gitlab.jfronny.commons.*;
import io.gitlab.jfronny.commons.serialize.gson.api.*;
import io.gitlab.jfronny.inceptum.model.inceptum.*;
import io.gitlab.jfronny.commons.OSUtils;
import java.io.*;
import java.net.*;
import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.*;
public class MetaHolder {
public static final InceptumVersion VERSION;
public static final Path BASE_PATH;
static {
try (InputStream is = MetaHolder.class.getClassLoader().getResourceAsStream("version.json");
InputStreamReader isr = new InputStreamReader(is)) {
VERSION = GsonHolder.getGson().fromJson(isr, InceptumVersion.class);
if (System.getProperty("inceptum.base") == null) {
Path runDir = getRunDir();
BASE_PATH = VERSION.isRelease && !Files.exists(runDir)
? getConfigPath().resolve("Inceptum")
: runDir;
}
else {
BASE_PATH = Paths.get(System.getProperty("inceptum.base"));
}
} catch (IOException e) {
throw new RuntimeException("Could not get version info", e);
if (System.getProperty("inceptum.base") == null) {
Path runDir = getRunDir();
BASE_PATH = BuildMetadata.IS_RELEASE && !Files.exists(runDir)
? getConfigPath().resolve("Inceptum")
: runDir;
} else {
BASE_PATH = Paths.get(System.getProperty("inceptum.base"));
}
}
public static final Path ACCOUNTS_PATH = BASE_PATH.resolve("accounts.json");
public static final Path CONFIG_PATH = BASE_PATH.resolve("inceptum.json");
public static final Path NATIVES_DIR = BASE_PATH.resolve("natives");
@ -37,7 +29,7 @@ public class MetaHolder {
public static final Path ASSETS_DIR = BASE_PATH.resolve("assets");
public static final Path INSTANCE_DIR = BASE_PATH.resolve("instances");
public static final Path CACHE_DIR = BASE_PATH.resolve("cache");
private static boolean isWrapper = false;
private static boolean isWrapper = false; //TODO move to build-time argument and download correct file in wrapper
private static Path getConfigPath() {
return switch (OSUtils.TYPE) {
@ -58,7 +50,7 @@ public class MetaHolder {
if (Files.exists(simpleRunDir)) return simpleRunDir;
URL url = MetaHolder.class.getProtectionDomain().getCodeSource().getLocation();
String p = url.getPath();
if (p.endsWith(".jar") && !p.endsWith("/build/libs/wrapper-" + VERSION.version + ".jar")) {
if (p.endsWith(".jar") && !p.endsWith("/build/libs/wrapper-" + BuildMetadata.VERSION + ".jar")) {
try {
return new File(url.toURI()).toPath().getParent().resolve("run");
} catch (URISyntaxException e) {

View File

@ -0,0 +1,100 @@
package io.gitlab.jfronny.inceptum.common;
import io.gitlab.jfronny.commons.HashUtils;
import io.gitlab.jfronny.commons.HttpUtils;
import io.gitlab.jfronny.commons.cache.FileBackedOperationResultCache;
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
import io.gitlab.jfronny.commons.throwable.ThrowingSupplier;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
public class Net {
private static final FileBackedOperationResultCache OBJECT_CACHE = new FileBackedOperationResultCache(MetaHolder.CACHE_DIR);
public static byte[] downloadData(String url) throws IOException, URISyntaxException {
try (InputStream is = HttpUtils.get(url).sendInputStream()) {
return is.readAllBytes();
}
}
public static byte[] downloadData(String url, String sha1) throws IOException, URISyntaxException {
byte[] buf = downloadData(url);
if (sha1 == null) return buf;
if (!HashUtils.sha1(buf).equals(sha1)) throw new IOException("Invalid hash");
return buf;
}
public static <T> T downloadObject(String url, Class<T> type) throws IOException {
return downloadObject(url, type, true);
}
public static <T> T downloadObject(String url, Class<T> type, boolean cache) throws IOException {
return downloadObject(url, () -> HttpUtils.get(url).sendString(), type, cache);
}
public static <T> T downloadObject(String url, Type type) throws IOException {
return downloadObject(url, type, true);
}
public static <T> T downloadObject(String url, Type type, String apiKey) throws IOException {
return downloadObject(url, () -> HttpUtils.get(url).header("x-api-key", apiKey).sendString(), type, true);
}
public static <T> T downloadObject(String url, Type type, boolean cache) throws IOException {
return downloadObject(url, () -> HttpUtils.get(url).sendString(), type, cache);
}
public static <T> T downloadObject(String url, String sha1, Class<T> type) throws IOException {
return downloadObject(url, sha1, type, true);
}
public static <T> T downloadObject(String url, String sha1, Class<T> type, boolean cache) throws IOException {
return downloadObject(url, () -> downloadString(url, sha1), type, cache);
}
private static <T> T downloadObject(String url, ThrowingSupplier<String, Exception> sourceString, Type type, boolean cache) throws IOException {
try {
ThrowingSupplier<T, Exception> builder = () -> GsonHolder.getGson().fromJson(sourceString.get(), type);
return cache ? OBJECT_CACHE.get(HashUtils.sha1(url.getBytes(StandardCharsets.UTF_8)), builder, type) : builder.get();
} catch (Exception e) {
throw new IOException("Could not download object and no cache exists", e);
}
}
public static String buildUrl(String host, String url, Map<String, String> params) {
StringBuilder res = new StringBuilder(host);
if (res.toString().endsWith("/")) res = new StringBuilder(res.substring(0, res.length() - 1));
if (url.startsWith("/")) res.append(url);
else res.append("/").append(url);
int i = 0;
for (Map.Entry<String, String> entry : params.entrySet()) {
res.append(i++ == 0 ? '?' : '&')
.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
.append('=')
.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
}
return res.toString();
}
public static String downloadString(String url, String sha1) throws IOException, URISyntaxException {
return new String(downloadData(url, sha1), StandardCharsets.UTF_8);
}
public static void downloadFile(String url, Path path) throws IOException, URISyntaxException {
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
Files.write(path, downloadData(url));
}
public static void downloadFile(String url, String sha1, Path path) throws IOException, URISyntaxException {
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
Files.write(path, downloadData(url, sha1));
}
}

View File

@ -0,0 +1,15 @@
package io.gitlab.jfronny.inceptum.common;
/**
* Class containing methods for nop lambdas. Use these instead of () -> {}
*/
public class R {
public static void nop() {
}
public static void nop(Object a1) {
}
public static void nop(Object a1, Object a2) {
}
}

View File

@ -1,12 +1,9 @@
package io.gitlab.jfronny.inceptum.util;
package io.gitlab.jfronny.inceptum.common;
import io.gitlab.jfronny.commons.ComparableVersion;
import io.gitlab.jfronny.commons.HttpUtils;
import io.gitlab.jfronny.inceptum.model.gitlab.*;
import io.gitlab.jfronny.inceptum.model.inceptum.InceptumVersion;
import io.gitlab.jfronny.inceptum.model.inceptum.UpdateChannel;
import io.gitlab.jfronny.inceptum.model.inceptum.UpdateInfo;
import io.gitlab.jfronny.inceptum.util.api.GitlabApi;
import io.gitlab.jfronny.inceptum.common.api.GitlabApi;
import io.gitlab.jfronny.inceptum.common.model.gitlab.*;
import io.gitlab.jfronny.inceptum.common.model.inceptum.*;
import java.io.IOException;
import java.net.URISyntaxException;
@ -27,19 +24,19 @@ public class UpdateChecker {
ComparableVersion experimentalVersion = null;
GitlabPackage stable = null;
ComparableVersion stableVersion = null;
packageLoop: for (GitlabPackage info : GitlabApi.getPackages(project)) {
packageLoop:
for (GitlabPackage info : GitlabApi.getPackages(project)) {
if (info.status.equals("default") && info.name.equals("io/gitlab/jfronny/inceptum/Inceptum")) {
for (GitlabPipeline pipeline : info.pipelines) {
for (GitlabJob job : GitlabApi.getJobs(project, pipeline.id)) {
if (!job.name.equals("build_test")) continue;
try {
InceptumVersion iv = HttpUtils.get(GitlabApi.PROJECTS + project.id + "/jobs/" + job.id + "/artifacts/version.json").sendSerialized(InceptumVersion.class);
VersionMetadata iv = Net.downloadObject(GitlabApi.PROJECTS + project.id + "/jobs/" + job.id + "/artifacts/version.json", VersionMetadata.class);
if (iv.jvm > jvm) {
Utils.LOGGER.error("A newer JVM is required to use the latest inceptum version. Please update!");
continue packageLoop;
}
}
catch (IOException | URISyntaxException e) {
} catch (IOException e) {
continue packageLoop;
}
}
@ -59,8 +56,7 @@ public class UpdateChecker {
}
if (experimental == null) {
throw new IOException("No version could be found");
}
else if (stable == null && channel == UpdateChannel.Stable) {
} else if (stable == null && channel == UpdateChannel.Stable) {
channel = UpdateChannel.CI;
channelInvalid.accept(channel);
}
@ -76,7 +72,8 @@ public class UpdateChecker {
GitlabPackageFile file = GitlabApi.getFile(project, info, f -> f.file_name.endsWith('-' + flavor + ".jar"));
if (file == null)
Utils.LOGGER.error("No valid package was discovered");
else return new UpdateInfo("https://gitlab.com/" + project.path_with_namespace + "/-/package_files/" + file.id + "/download", file.file_sha1, new ComparableVersion(info.version));
else
return new UpdateInfo("https://gitlab.com/" + project.path_with_namespace + "/-/package_files/" + file.id + "/download", file.file_sha1, new ComparableVersion(info.version));
} catch (IOException | URISyntaxException e) {
Utils.LOGGER.error("Could not check for updates", e);
}

View File

@ -0,0 +1,53 @@
package io.gitlab.jfronny.inceptum.common;
import io.gitlab.jfronny.commons.OSUtils;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.commons.log.Logger;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.util.regex.Pattern;
public class Utils {
public static final int CACHE_SIZE = 128;
public static final Pattern VALID_FILENAME = Pattern.compile("[a-zA-Z0-9_\\-.][a-zA-Z0-9 _\\-.]*[a-zA-Z0-9_\\-.]");
public static final Logger LOGGER = Logger.forName("Inceptum");
private static ClassLoader SYSTEM_LOADER = ClassLoader.getSystemClassLoader();
public static void openWebBrowser(URI uri) {
try {
if (OSUtils.TYPE == OSUtils.Type.LINUX && OSUtils.executablePathContains("xdg-open")) {
Runtime.getRuntime().exec(new String[]{"xdg-open", uri.toString()});
} else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(uri);
}
} catch (Exception e) {
Utils.LOGGER.error("Error opening web browser!", e);
}
}
public static void openFile(File file) {
try {
if (OSUtils.TYPE == OSUtils.Type.LINUX && OSUtils.executablePathContains("xdg-open")) {
Runtime.getRuntime().exec(new String[]{"xdg-open", file.getAbsoluteFile().toString()});
} else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().open(file);
}
} catch (Exception e) {
Utils.LOGGER.error("Error opening web browser!", e);
}
}
public static FileSystem openZipFile(Path zip, boolean create) throws IOException, URISyntaxException {
return JFiles.openZipFile(zip, create, SYSTEM_LOADER);
}
public static void setSystemLoader(ClassLoader loader) {
SYSTEM_LOADER = loader;
}
}

View File

@ -1,11 +1,8 @@
package io.gitlab.jfronny.inceptum.util.api;
package io.gitlab.jfronny.inceptum.common.api;
import io.gitlab.jfronny.commons.HttpUtils;
import io.gitlab.jfronny.gson.reflect.TypeToken;
import io.gitlab.jfronny.inceptum.model.gitlab.GitlabJob;
import io.gitlab.jfronny.inceptum.model.gitlab.GitlabPackage;
import io.gitlab.jfronny.inceptum.model.gitlab.GitlabPackageFile;
import io.gitlab.jfronny.inceptum.model.gitlab.GitlabProject;
import io.gitlab.jfronny.inceptum.common.model.gitlab.*;
import java.io.IOException;
import java.lang.reflect.Type;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.gitlab;
package io.gitlab.jfronny.inceptum.common.model.gitlab;
public class GitlabArtifact {
public String file_type;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.gitlab;
package io.gitlab.jfronny.inceptum.common.model.gitlab;
import java.util.Date;
import java.util.List;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.gitlab;
package io.gitlab.jfronny.inceptum.common.model.gitlab;
import java.util.Date;
import java.util.List;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.gitlab;
package io.gitlab.jfronny.inceptum.common.model.gitlab;
import java.util.Date;
import java.util.List;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.gitlab;
package io.gitlab.jfronny.inceptum.common.model.gitlab;
import java.util.Date;
import java.util.List;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.gitlab;
package io.gitlab.jfronny.inceptum.common.model.gitlab;
import java.util.Date;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.gitlab;
package io.gitlab.jfronny.inceptum.common.model.gitlab;
import java.util.Date;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.gitlab;
package io.gitlab.jfronny.inceptum.common.model.gitlab;
public class GitlabRunner {
public Long id;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.gitlab;
package io.gitlab.jfronny.inceptum.common.model.gitlab;
public class GitlabUser {
public long id;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.inceptum;
package io.gitlab.jfronny.inceptum.common.model.inceptum;
import java.util.Map;

View File

@ -0,0 +1,5 @@
package io.gitlab.jfronny.inceptum.common.model.inceptum;
public enum UpdateChannel {
Stable, CI
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.model.inceptum;
package io.gitlab.jfronny.inceptum.common.model.inceptum;
import io.gitlab.jfronny.commons.ComparableVersion;

View File

@ -1,10 +1,9 @@
package io.gitlab.jfronny.inceptum.model.inceptum;
package io.gitlab.jfronny.inceptum.common.model.inceptum;
import io.gitlab.jfronny.commons.ComparableVersion;
public class InceptumVersion {
public class VersionMetadata {
public ComparableVersion version;
public String flavor;
public Boolean isPublic;
public Boolean isRelease;
public Integer jvm;

View File

@ -1,5 +0,0 @@
package io.gitlab.jfronny.inceptum.model.inceptum;
public enum UpdateChannel {
Stable, CI
}

View File

@ -1,275 +0,0 @@
package io.gitlab.jfronny.inceptum.util;
import io.gitlab.jfronny.commons.*;
import io.gitlab.jfronny.commons.io.MultiAccessFileSystem;
import io.gitlab.jfronny.commons.log.Logger;
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
import io.gitlab.jfronny.commons.throwable.ThrowingSupplier;
import io.gitlab.jfronny.inceptum.util.cache.GsonFileCache;
import java.awt.*;
import java.io.*;
import java.lang.reflect.Type;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Stream;
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 Logger LOGGER = Logger.forName("Inceptum");
private static ClassLoader SYSTEM_LOADER = ClassLoader.getSystemClassLoader();
private static final GsonFileCache OBJECT_CACHE = new GsonFileCache(MetaHolder.CACHE_DIR);
public static byte[] downloadData(String url) throws IOException, URISyntaxException {
try (InputStream is = HttpUtils.get(url).sendInputStream()) {
return is.readAllBytes();
}
}
public static byte[] downloadData(String url, String sha1) throws IOException, URISyntaxException {
byte[] buf = downloadData(url);
if (sha1 == null) return buf;
if (!HashUtils.sha1(buf).equals(sha1)) throw new IOException("Invalid hash");
return buf;
}
public static <T> T downloadObject(String url, Class<T> type) throws IOException {
return downloadObject(url, type, true);
}
public static <T> T downloadObject(String url, Class<T> type, boolean cache) throws IOException {
return downloadObject(url, () -> HttpUtils.get(url).sendString(), type, cache);
}
public static <T> T downloadObject(String url, Type type) throws IOException {
return downloadObject(url, type, true);
}
public static <T> T downloadObject(String url, Type type, String apiKey) throws IOException {
return downloadObject(url, () -> HttpUtils.get(url).header("x-api-key", apiKey).sendString(), type, true);
}
public static <T> T downloadObject(String url, Type type, boolean cache) throws IOException {
return downloadObject(url, () -> HttpUtils.get(url).sendString(), type, cache);
}
public static <T> T downloadObject(String url, String sha1, Class<T> type) throws IOException {
return downloadObject(url, sha1, type, true);
}
public static <T> T downloadObject(String url, String sha1, Class<T> type, boolean cache) throws IOException {
return downloadObject(url, () -> downloadString(url, sha1), type, cache);
}
private static <T> T downloadObject(String url, ThrowingSupplier<String, Exception> sourceString, Type type, boolean cache) throws IOException {
try {
ThrowingSupplier<T, Exception> builder = () -> GsonHolder.getGson().fromJson(sourceString.get(), type);
return cache ? OBJECT_CACHE.get(HashUtils.sha1(url.getBytes(StandardCharsets.UTF_8)), builder, type) : builder.get();
} catch (Exception e) {
throw new IOException("Could not download object and no cache exists", e);
}
}
public static String buildUrl(String host, String url, Map<String, String> params) {
StringBuilder res = new StringBuilder(host);
if (res.toString().endsWith("/")) res = new StringBuilder(res.substring(0, res.length() - 1));
if (url.startsWith("/")) res.append(url);
else res.append("/").append(url);
int i = 0;
for (Map.Entry<String, String> entry : params.entrySet()) {
res.append(i++ == 0 ? '?' : '&')
.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
.append('=')
.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
}
return res.toString();
}
public static <T> T loadObject(Path file, Class<T> type) throws IOException {
try (BufferedReader br = Files.newBufferedReader(file)) {
return GsonHolder.getGson().fromJson(br, type);
}
}
public static <T> T loadObject(Path file, Type type) throws IOException {
try (BufferedReader br = Files.newBufferedReader(file)) {
return GsonHolder.getGson().fromJson(br, type);
}
}
public static <T> void writeObject(Path file, T object) throws IOException {
try (BufferedWriter bw = Files.newBufferedWriter(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
GsonHolder.getGson().toJson(object, bw);
}
}
public static String downloadString(String url, String sha1) throws IOException, URISyntaxException {
return new String(downloadData(url, sha1), StandardCharsets.UTF_8);
}
public static void downloadFile(String url, Path path) throws IOException, URISyntaxException {
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
Files.write(path, downloadData(url));
}
public static void downloadFile(String url, String sha1, Path path) throws IOException, URISyntaxException {
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
Files.write(path, downloadData(url, sha1));
}
public static void clearDirectory(Path path) throws IOException {
clearDirectory(path, p -> true);
}
public static void clearDirectory(Path path, Predicate<Path> shouldDelete) throws IOException {
if (!Files.exists(path)) return;
try {
Utils.ls(path, p -> {
if (Files.isDirectory(p)) {
try {
if (shouldDelete.test(p))
deleteRecursive(p, shouldDelete);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
else {
try {
if (shouldDelete.test(p))
Files.delete(p);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
} catch (Throwable t) {
throw new IOException("Could not clear directory", t);
}
}
public static void deleteRecursive(Path path) throws IOException {
deleteRecursive(path, p -> true);
}
public static void deleteRecursive(Path path, Predicate<Path> shouldDelete) throws IOException {
if (Files.isDirectory(path)) {
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;
if (shouldDelete.test(file))
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;
if (shouldDelete.test(dir) && ls(dir).isEmpty()) {
Files.delete(dir);
}
return FileVisitResult.CONTINUE;
}
});
}
else Files.delete(path);
}
public static void copyContent(Path source, Path destination) throws IOException {
copyContent(source, destination, StandardCopyOption.COPY_ATTRIBUTES);
}
public static void copyContent(Path source, Path destination, CopyOption... copyOptions) throws IOException {
if (!Files.exists(destination)) Files.createDirectories(destination);
if (Files.isDirectory(source)) {
try (Stream<Path> paths = Files.walk(source)) {
for (Path path : paths.toList()) {
if (source.equals(path)) continue;
Path d = destination.resolve(source.relativize(path).toString());
if (Files.exists(d)) continue;
if (Files.isDirectory(d)) Files.createDirectories(d);
else Files.copy(path, d);
}
}
} else if (Files.exists(source)) {
Path target = destination.resolve(source.getFileName().toString());
if (!Files.exists(target)
|| Arrays.asList(copyOptions).contains(StandardCopyOption.REPLACE_EXISTING))
Files.copy(source, target, copyOptions);
} else {
throw new FileNotFoundException(source.toAbsolutePath().toString());
}
}
public static void openWebBrowser(URI uri) {
try {
if (OSUtils.TYPE == OSUtils.Type.LINUX && OSUtils.executablePathContains("xdg-open")) {
Runtime.getRuntime().exec(new String[]{"xdg-open", uri.toString()});
} else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(uri);
}
} catch (Exception e) {
Utils.LOGGER.error("Error opening web browser!", e);
}
}
public static void openFile(File file) {
try {
if (OSUtils.TYPE == OSUtils.Type.LINUX && OSUtils.executablePathContains("xdg-open")) {
Runtime.getRuntime().exec(new String[]{"xdg-open", file.getAbsoluteFile().toString()});
} else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().open(file);
}
} catch (Exception e) {
Utils.LOGGER.error("Error opening web browser!", e);
}
}
public static List<Path> ls(Path dir) throws IOException {
try (Stream<Path> sp = Files.list(dir)) {
return sp.toList();
}
}
public static String[] lsVi(Path dir) throws IOException {
try (Stream<Path> sp = Files.list(dir)) {
return sp.map(p -> Files.isDirectory(p) ? p.getFileName().toString() + "/" : p.getFileName().toString()).toArray(String[]::new);
}
}
public static List<Path> ls(Path dir, Predicate<Path> predicate) throws IOException {
try (Stream<Path> sp = Files.list(dir); Stream<Path> fi = sp.filter(predicate)) {
return fi.toList();
}
}
public static <TEx extends Exception> void ls(Path dir, ThrowingConsumer<Path, TEx> consumer) throws IOException, TEx {
try (Stream<Path> sp = Files.list(dir)) {
for (Path path : sp.toList()) consumer.accept(path);
}
}
private static final Map<Path, MultiAccessFileSystem> zipFsCache = new HashMap<>();
public static FileSystem openZipFile(Path zip, boolean create) throws IOException, URISyntaxException {
synchronized (zipFsCache) {
if (!zipFsCache.containsKey(zip) || zipFsCache.get(zip).isClosed()) {
URI fileUri = zip.toUri();
zipFsCache.put(zip, MultiAccessFileSystem.create(new URI("jar:" + fileUri.getScheme(), fileUri.getPath(), null), create ? Map.of("create", "true") : Map.of(), SYSTEM_LOADER));
}
return zipFsCache.get(zip).createLens();
}
}
public static void setSystemLoader(ClassLoader loader) {
SYSTEM_LOADER = loader;
}
}

View File

@ -1,41 +0,0 @@
package io.gitlab.jfronny.inceptum.util.cache;
import io.gitlab.jfronny.inceptum.util.Utils;
import java.io.Closeable;
import java.io.IOException;
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
public class CachingGsonFile<T> implements Closeable {
private final Path filePath;
private final Class<T> type;
private final WatchService service;
private T cache = null;
public CachingGsonFile(Path filePath, Class<T> type) throws IOException {
this.filePath = filePath;
this.type = type;
this.service = FileSystems.getDefault().newWatchService();
filePath.getParent().register(service, ENTRY_MODIFY);
}
public T get() throws IOException {
WatchKey key = service.poll();
boolean update = cache == null;
if (key != null) {
for (WatchEvent<?> event : key.pollEvents()) {
update |= event.context().equals(filePath);
}
key.reset();
}
if (update) cache = Utils.loadObject(filePath, type);
return cache;
}
@Override
public void close() throws IOException {
service.close();
}
}

View File

@ -1,55 +0,0 @@
package io.gitlab.jfronny.inceptum.util.cache;
import io.gitlab.jfronny.commons.throwable.ThrowingSupplier;
import io.gitlab.jfronny.inceptum.util.Utils;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.ConcurrentHashMap;
public class GsonFileCache {
private final ConcurrentHashMap<String, Object> container = new ConcurrentHashMap<>();
private final Path cacheDir;
public GsonFileCache(Path cacheDir) {
this.cacheDir = cacheDir;
}
public void remove(String key) {
container.remove(key);
try {
Files.delete(cacheDir.resolve(key));
} catch (IOException e) {
Utils.LOGGER.error("Could not remove cache entry", e);
}
}
public void clear() {
container.clear();
try {
Utils.ls(cacheDir, Files::delete);
} catch (IOException e) {
Utils.LOGGER.error("Could not clear cache backend", e);
}
}
public <T, TEx extends Throwable> T get(String key, ThrowingSupplier<T, TEx> builder, Type klazz) throws TEx {
if (!container.containsKey(key)) {
Path cd = cacheDir.resolve(key);
if (Files.exists(cd)) {
try {
T value = Utils.loadObject(cd, klazz);
Utils.writeObject(cd, value);
container.put(key, value);
} catch (IOException e) {
Utils.LOGGER.error("Could not read cache", e);
}
}
else container.put(key, builder.get());
}
//noinspection unchecked
return (T) container.get(key);
}
}

View File

@ -1,25 +0,0 @@
package io.gitlab.jfronny.inceptum.util.cache;
import io.gitlab.jfronny.commons.throwable.ThrowingSupplier;
import java.util.concurrent.ConcurrentHashMap;
public class MemoryCache<TKey, TValue> {
private final ConcurrentHashMap<TKey, TValue> container = new ConcurrentHashMap<>();
public void remove(TKey key) {
container.remove(key);
}
public void clear() {
container.clear();
}
public void write() {
}
public <TEx extends Throwable> TValue get(TKey key, ThrowingSupplier<TValue, TEx> builder) throws TEx {
if (!container.containsKey(key)) container.put(key, builder.get());
return container.get(key);
}
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false">
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
<statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{HH:mm:ss.SSS} %boldCyan(%thread) %boldGreen(%logger{0}) %highlight(%level) %msg%n</pattern>
@ -15,12 +15,12 @@
</layout>
</appender>
<appender name="MEMORY" class="io.gitlab.jfronny.inceptum.util.MapAppender">
<appender name="MEMORY" class="io.gitlab.jfronny.inceptum.common.MapAppender">
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
<appender-ref ref="MEMORY" />
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
<appender-ref ref="MEMORY"/>
</root>
</configuration>

View File

@ -1,7 +0,0 @@
{
"version": "${version}",
"flavor": "${flavor}",
"isPublic": ${isPublic},
"isRelease": ${isRelease},
"jvm": ${jvm}
}

View File

@ -3,6 +3,7 @@ Inceptum provides a CLI which performs similar functions to the GUI. If you have
To view up-to-date information on the commands provided by Inceptum, run `inceptum help` or `inceptum help <command>`, this page is intended to explain more advanced features
## The inceptum wrapper
Inceptum Wrapper looks through the libraries dir and launches the latest available Inceptum version.
If it doesn't find a usable version, it will download the latest from GitLab.
Launching is performed through a custom ClassLoader and the wrapper command is prepended to the arguments provided by the user.
@ -13,15 +14,19 @@ It sets an internal flag and launches the command provided in its arguments.
Manually invoking this command WILL cause problems, so a check has been implemented that should prevent this from starting Inceptum in unintended environments.
## The "batch" command
This command will go through every line in the file provided in its arguments and executes the command written there.
It is intended to be used in scripts that only want to run inceptum once, such as the systemd unit in the AUR package.
The batch command has the additional advantage of allowing caches to stay loaded between commands, making execution faster.
For example,
```
git pull icesrv
run server restart icesrv
```
is equivalent to the bash script
```shell
#!/bin/sh
inceptum git pull icesrv

View File

@ -1,8 +1,10 @@
# File Formats
Inceptum uses several json formats to store metadata and configs.
All of these are subject to change, though automatic migrations will likely be provided.
## inceptum.json (Main Config)
```json
{
// Whether to show snapshots in the version selector for new instances
@ -49,12 +51,15 @@ All of these are subject to change, though automatic migrations will likely be p
```
## accounts.json
Do not EVER use this file manually!
NEVER upload it anywhere!
It stores your minecraft account login and CAN BE USED TO IMPERSONATE YOU!
## instance.json (Instance Metadata)
Please note that all entries except for "version" are optional
```json
{
// The version to use for launching this
@ -90,6 +95,7 @@ Please note that all entries except for "version" are optional
```
## *.imod (Mod Metadata)
```json
{
// Where the JAR file for this mod can be obtained

View File

@ -1,7 +1,9 @@
# Installing
Inceptum can be installed in a number of ways, all of which are documented below.
## Simple installation
First, download the Inceptum build appropriate for your system:
- [Windows x86_64](https://gitlab.com/JFronny/inceptum/-/jobs/artifacts/master/raw/latest-windows.jar?job=build_test)
@ -18,16 +20,19 @@ Inceptum will use your config directory ($XDG_CONFIG_HOME, ~/.config/Inceptum, %
If you want them somewhere else, read on
### Config files in current directory
If the Inceptum jar detects a directory called "run" in the directory it is placed in,
it will use that instead of the users config directory.
Create a directory (= Folder) next to the inceptum jar.
### Config files in a custom location
You may specify the java VM parameter `-Dinceptum.base=$DIRECTORY` to use a custom directory for Inceptum.
If this parameter is specified, all other locations will be ignored.
## Simple installation with updates
To use automatic updates, you must use the Inceptum Wrapper.
Simply launch this [cross-platform jar](https://gitlab.com/JFronny/inceptum/-/jobs/artifacts/master/raw/wrapper.jar?job=build_test)
and Inceptum will launch as described above (though the initial startup may take a bit longer). The same rules for config locations apply.
@ -37,12 +42,14 @@ which uses fabric-installer-native-bootstrap to locate the JVM used by the offic
Please be aware that this is pretty much untested
## Installation from the AUR
Inceptum is available in the AUR as [`inceptum-git`](https://aur.archlinux.org/packages/inceptum-git)
If you use arch linux or a derivative, you may use this package instead of a manual installation.
It also includes a template systemd service which you can copy and customize to launch your minecraft server.
For more information on the syntax of this services config file, go [here](Commands.md)
## Using Inceptum on Windows without OpenGL drivers
Download the portable build from [here](https://gitlab.com/jfmods/inceptum/-/jobs/artifacts/master/raw/portable.7z?job=portable)
This archive includes Inceptum using the Inceptum wrapper, a JVM and a Mesa build for CPU-based graphics.
Please be aware that using this WILL result in worse performance.

31
docs/Modules.md Normal file
View File

@ -0,0 +1,31 @@
# Modules
Inceptum is split into multiple separate but interdependent modules.
The purpose of this page is to list them, explain their purpose and where to get them
## common
This module contains common, platform-agnostic code shared between the launcher and the wrapper.
It can be obtained through the maven.
## launcher
This module contains common, platform-agnostic code between all frontends of the launcher.
It can be obtained through the maven.
## launcher-cli
This module contains the platform-agnostic command-line interface for the launcher
It can be obtained through the maven or the shadowed Inceptum jar
## launcher-imgui
This module contains a dear-imgui-based frontend for Inceptum.
Builds of this module are platform-specific and dependents must manually ensure the correct imgui and lwjgl natives are imported.
A build without natives can be obtained through the maven and a build with natives through the shadowed Inceptum jar
## launcher-shadowed/Inceptum
This module builds a shadowed jar of launcher-cli and launcher-imgui to be used by normal users.
It also adds additional, platform-specific commands to the CLI.
A build can be obtained through the maven (with the correct suffix) or as a jar with shadowed dependencies.
Windows users can also obtain a binary built using fabric-installer-native-bootstrap.
## wrapper
This module serves the purpose of downloading the components necessary for executing Inceptum on the current platform.
A build with shadowed dependencies can be obtained through the maven (with the suffix "all") or as a jar.
Windows users can also obtain a binary built using fabric-installer-native-bootstrap.

View File

@ -1,4 +1,5 @@
# About
Inceptum is advanced FOSS Launcher for Minecraft written in Java
Features:

View File

@ -1,14 +1,17 @@
# Syncing instances
Inceptum supports syncing repositories between instances through git.
This is roughly comparable to updatable modpacks in other launchers.
There are two workflows for this, you can choose one based on your use case.
## Uploading a local pack to a game server
This approach assumes that your intention is to have a game server running Inceptum
and to regularly push updates built and tested in an Inceptum instance on your PC.
To set this up, initialize a repo on your server and clone it locally
Server:
```shell
cd /srv/inceptum/instances
mkdir icesrv
@ -16,7 +19,9 @@ cd icesrv
git init
git config receive.denyCurrentBranch ignore
```
Client:
```shell
git clone inceptum@example.com:/srv/inceptum/instances/icesrv
cd icesrv
@ -26,7 +31,9 @@ git add .
git commit -m "Initial commit"
git push
```
After that, you can use a script similar to the following to push changes:
```shell
git push -u origin master
rconc icesrv stop
@ -34,10 +41,12 @@ sleep 1
ssh -t inceptum@example.com "cd /srv/inceptum/instances/icesrv; git reset --hard"
ssh -t admin@example.com "sudo systemctl restart inceptum-icesrv"
```
icesrv is the name of the instance in this example and inceptum-icesrv is a systemd service based on the one included
in the AUR package.
## Providing a pack to multiple users
To do this, create a new repository on a git hosting site (like GitHub or GitLab) and push your local instance there.
Since a git repository is created for every instance, simply following the instructions for pushing an existing
repository or using any graphical tool is enough to set this up.

View File

@ -0,0 +1,11 @@
plugins {
id("inceptum.application-conventions")
}
application {
mainClass.set("io.gitlab.jfronny.inceptum.cli.CliMain")
}
dependencies {
implementation(project(":launcher"))
}

View File

@ -1,8 +1,9 @@
package io.gitlab.jfronny.inceptum.frontend.cli;
package io.gitlab.jfronny.inceptum.cli;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.common.MetaHolder;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import java.io.IOException;
import java.nio.file.Files;
@ -43,7 +44,7 @@ public abstract class BaseInstanceCommand extends Command {
}
InstanceMeta meta;
try {
meta = Utils.loadObject(instanceMetaPath, InstanceMeta.class);
meta = JFiles.readObject(instanceMetaPath, InstanceMeta.class);
} catch (IOException e) {
Utils.LOGGER.error("Could not read instance metadata", e);
return;

View File

@ -0,0 +1,45 @@
package io.gitlab.jfronny.inceptum.cli;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.launcher.api.account.MicrosoftAccount;
import java.io.IOException;
import java.util.Scanner;
import java.util.function.Consumer;
public class CliEnvBackend implements LauncherEnv.EnvBackend {
@Override
public void showError(String message, String title) {
Utils.LOGGER.error(message);
}
@Override
public void showError(String message, Throwable t) {
Utils.LOGGER.error(message, t);
}
@Override
public void showInfo(String message, String title) {
Utils.LOGGER.info(message);
}
@Override
public void showOkCancel(String message, String title, Runnable ok, Runnable cancel, boolean defaultCancel) {
Utils.LOGGER.info(message);
if (!defaultCancel) ok.run();
}
@Override
public void getInput(String prompt, String details, String defaultValue, Consumer<String> ok, Runnable cancel) throws IOException {
Scanner scanner = new Scanner(System.in);
System.out.println(prompt);
System.out.print("> ");
ok.accept(scanner.nextLine());
}
@Override
public void showLoginRefreshPrompt(MicrosoftAccount account) {
Utils.LOGGER.error("Could not launch using the selected account as its login has expired. Please log in again through the UI!");
}
}

View File

@ -0,0 +1,55 @@
package io.gitlab.jfronny.inceptum.cli;
import io.gitlab.jfronny.inceptum.cli.commands.*;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import java.util.*;
public class CliMain {
public static Command DEFAULT = new HelpCommand();
public static final List<Command> KNOWN_COMMANDS = new LinkedList<>(List.of(
DEFAULT,
new LaunchCommand(),
new ListCommand(),
new ModCommand(),
new ExportCommand(),
new JvmStateCommand(),
new BatchCommand(),
new WrapperCommand() //TODO remove once wrapper is a build flag
));
public static final Command COMMANDS_ROOT = new Command("Root command", "<command>", List.of(), KNOWN_COMMANDS) {
@Override
protected void invoke(CommandArgs args) {
throw new RuntimeException("Could not find command: " + args.get(0));
}
@Override
public CommandResolution resolve(CommandArgs args) {
if (args.length == 0) return new CommandResolution(DEFAULT, args, new ArrayList<>());
return super.resolve(args);
}
};
public static CommandResolution resolve(String[] args, boolean wrapped) {
return COMMANDS_ROOT.resolve(new CommandArgs(Arrays.asList(args), wrapped));
}
public static void main(String[] args) throws Exception {
LauncherEnv.checkClassLoaderState();
CommandResolution command = resolve(args, false);
if (command.command().enableLog()) {
Utils.LOGGER.info("Launching Inceptum v" + BuildMetadata.VERSION);
Utils.LOGGER.info("Loading from " + MetaHolder.BASE_PATH);
}
LauncherEnv.initialize(new CliEnvBackend());
try {
command.invoke();
} finally {
LauncherEnv.terminate();
}
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.cli;
package io.gitlab.jfronny.inceptum.cli;
import java.util.*;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.cli;
package io.gitlab.jfronny.inceptum.cli;
import java.util.*;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.cli;
package io.gitlab.jfronny.inceptum.cli;
import java.util.List;

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.cli;
package io.gitlab.jfronny.inceptum.cli;
import java.util.ArrayList;
import java.util.List;

View File

@ -1,15 +1,10 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.commons.ArgumentsTokenizer;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandResolution;
import io.gitlab.jfronny.inceptum.frontend.cli.Commands;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.cli.*;
import io.gitlab.jfronny.inceptum.common.Utils;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.*;
import java.util.LinkedHashSet;
import java.util.Set;
@ -37,7 +32,7 @@ public class BatchCommand extends Command {
}
try {
for (String line : Files.readAllLines(p)) {
CommandResolution resolution = Commands.resolve(ArgumentsTokenizer.tokenize(line), args.wrapped);
CommandResolution resolution = CliMain.resolve(ArgumentsTokenizer.tokenize(line), args.wrapped);
if (resolution.command() instanceof WrapperCommand)
throw new Exception("You may not use the wrapper command in a command batch");
resolved.add(resolution);

View File

@ -1,10 +1,11 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.inceptum.frontend.cli.*;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.InstanceExporter;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.cli.*;
import io.gitlab.jfronny.inceptum.common.R;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.system.export.InstanceExporter;
import io.gitlab.jfronny.inceptum.launcher.util.ProcessState;
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
import java.nio.file.Path;
import java.nio.file.Paths;
@ -29,7 +30,7 @@ public class ExportCommand extends BaseInstanceCommand {
if (args.length != 2) throw new IllegalAccessException("Too many arguments");
ProcessState state = new ProcessState();
ModsDirScanner mds = ModsDirScanner.get(instancePath.resolve("mods"), meta);
mds.runOnce((path, mod) -> {});
mds.runOnce(R::nop);
InstanceExporter.exportCurseZip(state, instancePath, meta, mds, Paths.get(args.get(0)), args.get(1));
}
@ -44,7 +45,7 @@ public class ExportCommand extends BaseInstanceCommand {
if (args.length != 1) throw new IllegalAccessException("Too many arguments");
ProcessState state = new ProcessState();
ModsDirScanner mds = ModsDirScanner.get(instancePath.resolve("mods"), meta);
mds.runOnce((path, mod) -> {});
mds.runOnce(R::nop);
InstanceExporter.exportMultiMCZip(state, instancePath, meta, mds, Paths.get(args.get(0)));
}
}

View File

@ -1,7 +1,7 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.inceptum.frontend.cli.*;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.cli.*;
import io.gitlab.jfronny.inceptum.common.BuildMetadata;
import java.util.List;
@ -9,16 +9,16 @@ public class HelpCommand extends Command {
public HelpCommand() {
super("Displays this screen", "[command]", "help");
}
@Override
protected void invoke(CommandArgs args) {
HelpBuilder help = new HelpBuilder();
if (args.length == 0) {
printHeader();
System.out.println("\nCommands:");
Commands.COMMANDS_ROOT.buildHelp(help);
}
else {
CommandResolution resolution = Commands.COMMANDS_ROOT.resolve(args);
CliMain.COMMANDS_ROOT.buildHelp(help);
} else {
CommandResolution resolution = CliMain.COMMANDS_ROOT.resolve(args);
if (resolution.resolvePath().isEmpty()) {
System.err.println("Could not find command matching your input");
invoke(new CommandArgs(List.of(), args.wrapped));
@ -32,6 +32,6 @@ public class HelpCommand extends Command {
}
private static void printHeader() {
System.out.println("Inceptum v" + MetaHolder.VERSION.version + " (" + MetaHolder.VERSION.flavor + ")");
System.out.println("Inceptum v" + BuildMetadata.VERSION);
}
}

View File

@ -1,7 +1,7 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.cli.Command;
import io.gitlab.jfronny.inceptum.cli.CommandArgs;
import java.net.URLClassLoader;
import java.util.Arrays;

View File

@ -1,23 +1,16 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.inceptum.frontend.cli.BaseInstanceCommand;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.InstanceLauncher;
import io.gitlab.jfronny.inceptum.util.InstanceLock;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.util.install.Steps;
import io.gitlab.jfronny.inceptum.cli.*;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.system.launch.InstanceLauncher;
import io.gitlab.jfronny.inceptum.launcher.util.InstanceLock;
import io.gitlab.jfronny.inceptum.launcher.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.launcher.system.install.Steps;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.*;
public class LaunchCommand extends BaseInstanceCommand {
private final boolean server;
@ -31,7 +24,7 @@ public class LaunchCommand extends BaseInstanceCommand {
new LaunchCommand("Explicitly launch a client", "client", false, false),
new LaunchCommand("Launch a server", "server", true, false,
new LaunchCommand("Restart the server if it stops", "restart", true, true)
)
)
));
this.server = false;
this.restart = false;
@ -64,8 +57,7 @@ public class LaunchCommand extends BaseInstanceCommand {
Steps.reDownload(instancePath, Steps.createProcessState());
if (server) {
InstanceLauncher.launch(instancePath, meta, InstanceLauncher.LaunchType.Server, restart, AccountManager.NULL_AUTH);
}
else {
} else {
AccountManager.loadAccounts();
InstanceLauncher.launchClient(instancePath, meta);
}

View File

@ -1,11 +1,12 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.InstanceLock;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.common.MetaHolder;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.cli.Command;
import io.gitlab.jfronny.inceptum.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.util.InstanceLock;
import java.io.IOException;
import java.nio.file.Files;
@ -19,7 +20,7 @@ public class ListCommand extends Command {
@Override
protected void invoke(CommandArgs args) throws IOException {
List<Path> paths = Utils.ls(MetaHolder.INSTANCE_DIR);
List<Path> paths = JFiles.list(MetaHolder.INSTANCE_DIR);
if (paths.isEmpty()) System.out.println("No instances are currently present");
for (Path path : paths) {
if (!Files.exists(path.resolve("instance.json"))) {
@ -33,7 +34,7 @@ public class ListCommand extends Command {
}
InstanceMeta instance;
try {
instance = Utils.loadObject(path.resolve("instance.json"), InstanceMeta.class);
instance = JFiles.readObject(path.resolve("instance.json"), InstanceMeta.class);
} catch (IOException e) {
Utils.LOGGER.error(" Could not load instance.json", e);
continue;

View File

@ -1,17 +1,15 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.commons.throwable.ThrowingBiFunction;
import io.gitlab.jfronny.inceptum.frontend.cli.BaseInstanceCommand;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.frontend.gui.window.AddModWindow;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.ModManager;
import io.gitlab.jfronny.inceptum.util.PathUtil;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.mds.IWModDescription;
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.cli.*;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.util.ModManager;
import io.gitlab.jfronny.inceptum.launcher.util.ModPath;
import io.gitlab.jfronny.inceptum.launcher.system.mds.IWModDescription;
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.launcher.system.source.ModSource;
import java.io.FileNotFoundException;
import java.io.IOException;
@ -80,6 +78,7 @@ public class ModCommand extends Command {
public static class ModRemoveCommand extends BaseInstanceCommand {
private final boolean ignoreDependencies;
public ModRemoveCommand() {
this("Removes mods from an instance", List.of("remove", "delete", "rm", "del"), List.of(
new ModRemoveCommand("Skip dependency checks", List.of("ignore-dependencies"), List.of(), true)
@ -132,7 +131,7 @@ public class ModCommand extends Command {
public ModUpdateCommand() {
this("Update mods in an instance", "<mod file>...", List.of("update", "upgrade", "up"), List.of(
new ModUpdateCommand("Update all mods in an instance", "", List.of("all"), List.of(), (args, instancePath) -> Set.copyOf(Utils.ls(instancePath)))
new ModUpdateCommand("Update all mods in an instance", "", List.of("all"), List.of(), (args, instancePath) -> Set.copyOf(JFiles.list(instancePath)))
), (args, instancePath) -> {
Set<Path> mods = new HashSet<>();
for (String arg : args) {
@ -180,8 +179,8 @@ public class ModCommand extends Command {
if (ms.isPresent()) {
try {
Utils.LOGGER.info("Updating to " + ms.get().getVersion());
Path imodPath = md.imod().isPresent() ? md.imod().get() : instancePath.resolve("mods").resolve(ms.get().getShortName() + PathUtil.EXT_IMOD);
AddModWindow.DownloadMeta dm = AddModWindow.download(ms.get(), imodPath, mds);
Path imodPath = md.imod().isPresent() ? md.imod().get() : instancePath.resolve("mods").resolve(ms.get().getShortName() + ModPath.EXT_IMOD);
ModManager.DownloadMeta dm = ModManager.download(ms.get(), imodPath, mds);
Files.delete(md.path());
if (md.imod().isPresent() && Files.exists(md.imod().get()))
Files.delete(md.imod().get());

View File

@ -1,7 +1,7 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
package io.gitlab.jfronny.inceptum.cli.commands;
import io.gitlab.jfronny.inceptum.frontend.cli.*;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.cli.*;
import io.gitlab.jfronny.inceptum.common.MetaHolder;
public class WrapperCommand extends Command {
public WrapperCommand() {
@ -18,7 +18,7 @@ public class WrapperCommand extends Command {
if (MetaHolder.isWrapper()) {
throw new IllegalStateException("The WrapperStrap classloader does not match the inceptum loader. Are you using the latest wrapper?");
}
return Commands.COMMANDS_ROOT.resolve(args);
return CliMain.COMMANDS_ROOT.resolve(args);
}
@Override

1
launcher-imgui/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
src/main/java/io/gitlab/jfronny/inceptum/imgui/ImBuildMetadata.java

View File

@ -0,0 +1,39 @@
plugins {
id("inceptum.application-conventions")
}
group = "io.gitlab.jfronny.inceptum"
version = "0.2.0-1662303777"
dependencies {
val flavor: String by rootProject.extra
val lwjglVersion: String by rootProject.extra
val imguiVersion: String by rootProject.extra
implementation(project(":launcher"))
implementation(platform("org.lwjgl:lwjgl-bom:$lwjglVersion"))
arrayOf("", "-opengl", "-glfw", "-tinyfd").forEach {
implementation("org.lwjgl:lwjgl$it:$lwjglVersion")
if (flavor == "windows" || flavor == "fat") implementation("org.lwjgl:lwjgl$it::natives-windows")
if (flavor == "linux" || flavor == "fat") implementation("org.lwjgl:lwjgl$it::natives-linux")
if (flavor == "macos" || flavor == "fat") implementation("org.lwjgl:lwjgl$it::natives-macos")
}
implementation("io.github.spair:imgui-java-binding:$imguiVersion") // https://github.com/SpaiR/imgui-java
implementation("io.github.spair:imgui-java-lwjgl3:$imguiVersion")
if (flavor == "windows" || flavor == "fat") implementation("io.github.spair:imgui-java-natives-windows:$imguiVersion")
if (flavor == "linux" || flavor == "fat") implementation("io.github.spair:imgui-java-natives-linux:$imguiVersion")
if (flavor == "macos" || flavor == "fat") implementation("io.github.spair:imgui-java-natives-macos:$imguiVersion")
}
projectDir.resolve("src/main/java/io/gitlab/jfronny/inceptum/imgui/ImBuildMetadata.java").writeText(
"""
package io.gitlab.jfronny.inceptum.imgui;
public class ImBuildMetadata {
public static final String FLAVOR = "${rootProject.extra["flavorProp"]}";
}
""".trimIndent())

View File

@ -0,0 +1,47 @@
package io.gitlab.jfronny.inceptum.imgui;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.imgui.window.MicrosoftLoginWindow;
import io.gitlab.jfronny.inceptum.imgui.window.dialog.AlertWindow;
import io.gitlab.jfronny.inceptum.imgui.window.dialog.TextBoxWindow;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.launcher.api.account.MicrosoftAccount;
import java.io.IOException;
import java.util.function.Consumer;
public class GuiEnvBackend implements LauncherEnv.EnvBackend {
@Override
public void showError(String message, String title) {
Utils.LOGGER.error(message);
GuiMain.WINDOWS.add(new AlertWindow(title, message));
}
@Override
public void showError(String message, Throwable t) {
Utils.LOGGER.error(message, t);
GuiMain.WINDOWS.add(new AlertWindow(message, t.toString()));
}
@Override
public void showInfo(String message, String title) {
Utils.LOGGER.info(message);
GuiMain.WINDOWS.add(new AlertWindow(title, message));
}
@Override
public void showOkCancel(String message, String title, Runnable ok, Runnable cancel, boolean defaultCancel) {
Utils.LOGGER.info(message);
GuiMain.WINDOWS.add(new AlertWindow(title, message, ok, cancel));
}
@Override
public void getInput(String prompt, String details, String defaultValue, Consumer<String> ok, Runnable cancel) throws IOException {
GuiMain.WINDOWS.add(new TextBoxWindow(prompt, details, defaultValue, ok, cancel));
}
@Override
public void showLoginRefreshPrompt(MicrosoftAccount account) {
GuiMain.open(new MicrosoftLoginWindow(account));
}
}

View File

@ -1,22 +1,21 @@
package io.gitlab.jfronny.inceptum;
package io.gitlab.jfronny.inceptum.imgui;
import imgui.ImGui;
import imgui.ImGuiIO;
import imgui.flag.ImGuiConfigFlags;
import imgui.gl3.ImGuiImplGl3;
import imgui.glfw.ImGuiImplGlfw;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.ConfigHolder;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
import org.lwjgl.glfw.Callbacks;
import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.glfw.GLFWVidMode;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateInfo;
import io.gitlab.jfronny.inceptum.imgui.window.MainWindow;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.imgui.window.Window;
import io.gitlab.jfronny.inceptum.launcher.Updater;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL32;
import org.lwjgl.system.MemoryStack;
@ -24,12 +23,13 @@ import org.lwjgl.system.MemoryUtil;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.IntBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
public class InceptumGui {
public class GuiMain {
public static final Set<Window> WINDOWS = new LinkedHashSet<>();
private static final ImGuiImplGlfw imGuiGlfw = new ImGuiImplGlfw();
private static final ImGuiImplGl3 imGuiGl3 = new ImGuiImplGl3();
@ -39,19 +39,52 @@ public class InceptumGui {
protected static long handle;
private static String glslVersion = null;
public static void main(CommandArgs args, Runnable exec) {
public static void main(String[] args) throws IOException {
LauncherEnv.checkClassLoaderState();
Utils.LOGGER.info("Launching Inceptum v" + BuildMetadata.VERSION + " (" + ImBuildMetadata.FLAVOR + ")");
Utils.LOGGER.info("Loading from " + MetaHolder.BASE_PATH);
LauncherEnv.initialize(new GuiEnvBackend());
try {
main(false);
} finally {
LauncherEnv.terminate();
}
}
public static void main(boolean wrapped) {
UpdateInfo update = Updater.getUpdate(ImBuildMetadata.FLAVOR);
AccountManager.loadAccounts();
Utils.LOGGER.info("Initializing UI");
try {
for (Path path : Utils.ls(MetaHolder.INSTANCE_DIR)) {
JFiles.listTo(MetaHolder.INSTANCE_DIR, path -> {
if (Files.exists(path.resolve("instance.json")))
ModsDirScanner.get(path.resolve("mods"), Utils.loadObject(path.resolve("instance.json"), InstanceMeta.class)).start();
}
ModsDirScanner.get(path.resolve("mods"), JFiles.readObject(path.resolve("instance.json"), InstanceMeta.class)).start();
});
} catch (IOException e) {
Utils.LOGGER.error("Could not initialize MDS");
}
init();
exec.run();
if (update == null) {
WINDOWS.add(new MainWindow());
} else if (wrapped) {
LauncherEnv.showOkCancel("An update was found. Should it be installed automatically?", "Update found", () -> {
try {
Updater.update(update, true);
exit();
} catch (IOException | URISyntaxException e) {
LauncherEnv.showError("Could not download update", e);
}
}, () -> WINDOWS.add(new MainWindow()));
} else {
LauncherEnv.showOkCancel("An update was found. Automatic installs are not supported without the wrapper but you can download it nonetheless", "Update found", () -> {
try {
Utils.openWebBrowser(new URI(update.url()));
exit();
} catch (URISyntaxException e) {
LauncherEnv.showError("Could not download update", e);
}
}, () -> WINDOWS.add(new MainWindow()));
}
run();
dispose();
}
@ -144,7 +177,7 @@ public class InceptumGui {
ImGuiIO io = ImGui.getIO();
io.addConfigFlags(ImGuiConfigFlags.ViewportsEnable);
io.setConfigViewportsNoAutoMerge(true);
try (InputStream is = Inceptum.class.getClassLoader().getResourceAsStream("font.ttf")) {
try (InputStream is = LauncherEnv.class.getClassLoader().getResourceAsStream("font.ttf")) {
assert is != null;
io.setFontDefault(io.getFonts().addFontFromMemoryTTF(is.readAllBytes(), 16f));
} catch (IOException e) {

View File

@ -1,23 +1,17 @@
package io.gitlab.jfronny.inceptum.frontend.gui.control;
package io.gitlab.jfronny.inceptum.imgui.control;
import imgui.ImGui;
import imgui.type.ImBoolean;
import imgui.type.ImInt;
import imgui.type.ImString;
import imgui.type.*;
import io.gitlab.jfronny.commons.cache.MemoryOperationResultCache;
import io.gitlab.jfronny.commons.tuple.Tuple;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.model.fabric.FabricVersionLoaderInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.LoaderInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionsList;
import io.gitlab.jfronny.inceptum.model.mojang.VersionsListInfo;
import io.gitlab.jfronny.inceptum.util.ConfigHolder;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.FabricMetaApi;
import io.gitlab.jfronny.inceptum.util.api.McApi;
import io.gitlab.jfronny.inceptum.util.cache.MemoryCache;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.imgui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.launcher.model.fabric.FabricVersionLoaderInfo;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.LoaderInfo;
import io.gitlab.jfronny.inceptum.launcher.model.mojang.*;
import io.gitlab.jfronny.inceptum.launcher.api.FabricMetaApi;
import io.gitlab.jfronny.inceptum.launcher.api.McApi;
import java.io.IOException;
import java.nio.file.Files;
@ -27,8 +21,8 @@ import java.util.function.Consumer;
public class InstanceManageControls {
private static final VersionsList VERSIONS = McApi.getVersions();
private static final MemoryCache<VersionsListInfo, List<FabricVersionLoaderInfo>> LOADER_INFO_CACHE = new MemoryCache<>();
private static final MemoryCache<Tuple<String, String>, VersionInfo> VERSION_INFO_CACHE = new MemoryCache<>();
private static final MemoryOperationResultCache<VersionsListInfo, List<FabricVersionLoaderInfo>> LOADER_INFO_CACHE = new MemoryOperationResultCache<>(Utils.CACHE_SIZE);
private static final MemoryOperationResultCache<Tuple<String, String>, VersionInfo> VERSION_INFO_CACHE = new MemoryOperationResultCache<>(Utils.CACHE_SIZE);
private final ImInt version = new ImInt(0);
private final ImString name = new ImString("", GuiUtil.INPUT_FIELD_LENGTH);
@ -131,7 +125,8 @@ public class InstanceManageControls {
public VersionInfo getVersionInfo() throws IOException {
return VERSION_INFO_CACHE.get(Tuple.of(selected.id, fabric.get() ? selectedFabric.loader.version : ""), () -> {
VersionInfo vi = McApi.getVersionInfo(selected);
if (fabric.get()) vi = FabricMetaApi.addFabric(vi, selectedFabric.loader.version, FabricMetaApi.FabricVersionInfoType.Both);
if (fabric.get())
vi = FabricMetaApi.addFabric(vi, selectedFabric.loader.version, FabricMetaApi.FabricVersionInfoType.Both);
return vi;
});
}

View File

@ -1,26 +1,23 @@
package io.gitlab.jfronny.inceptum.frontend.gui.control;
package io.gitlab.jfronny.inceptum.imgui.control;
import imgui.ImGui;
import imgui.flag.ImGuiTableFlags;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.window.edit.InstanceEditWindow;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.InstanceLauncher;
import io.gitlab.jfronny.inceptum.util.InstanceLock;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.cache.CachingGsonFile;
import io.gitlab.jfronny.inceptum.util.install.Steps;
import io.gitlab.jfronny.commons.cache.FileBackedRef;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.imgui.GuiMain;
import io.gitlab.jfronny.inceptum.imgui.window.edit.InstanceEditWindow;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.system.launch.InstanceLauncher;
import io.gitlab.jfronny.inceptum.launcher.util.InstanceLock;
import io.gitlab.jfronny.inceptum.launcher.system.install.Steps;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
public class InstanceView {
private static final Map<Path, CachingGsonFile<InstanceMeta>> metas = new HashMap<>();
private static final Map<Path, FileBackedRef<InstanceMeta>> metas = new HashMap<>();
public static void draw(List<Path> paths) {
if (ImGui.beginTable("Instances", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
@ -38,7 +35,8 @@ public class InstanceView {
}
InstanceMeta instance;
try {
if (!metas.containsKey(path)) metas.put(path, new CachingGsonFile<>(path.resolve("instance.json"), InstanceMeta.class));
if (!metas.containsKey(path))
metas.put(path, new FileBackedRef<>(path.resolve("instance.json"), InstanceMeta.class));
instance = metas.get(path).get();
} catch (IOException e) {
Utils.LOGGER.error("Could not load instance.json", e);
@ -65,7 +63,7 @@ public class InstanceView {
ImGui.tableNextColumn();
if (ImGui.button("Edit##" + path)) {
try {
InceptumGui.open(new InstanceEditWindow(path, instance));
GuiMain.open(new InstanceEditWindow(path, instance));
} catch (IOException e) {
Utils.LOGGER.error("Could not open instance edit window", e);
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.gui.control;
package io.gitlab.jfronny.inceptum.imgui.control;
import imgui.ImGui;

View File

@ -1,9 +1,9 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window;
package io.gitlab.jfronny.inceptum.imgui.window;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.common.BuildMetadata;
import io.gitlab.jfronny.inceptum.common.Utils;
import java.net.URI;
import java.net.URISyntaxException;
@ -15,15 +15,18 @@ public class AboutWindow extends Window {
@Override
public void draw() {
ImGui.text("Inceptum " + MetaHolder.VERSION.version + " Copyright (C) 2021 JFronny");
ImGui.text("Inceptum " + BuildMetadata.VERSION + " Copyright (C) 2021 JFronny");
ImGui.text("This program comes with ABSOLUTELY NO WARRANTY.");
ImGui.text("This is free software, and you are welcome to redistribute it under certain conditions.");
ImGui.separator();
if (!MetaHolder.VERSION.isPublic) ImGui.text("This is a custom build. No support will be provided");
else if (!MetaHolder.VERSION.jvm.equals(Runtime.version().feature())) ImGui.text("This build was designed for Java " + MetaHolder.VERSION.jvm + ", but you are using Java " + Runtime.version().feature() + ". No support will be provided");
else {
int vm = Runtime.version().feature();
if (!BuildMetadata.IS_PUBLIC) {
ImGui.text("This is a custom build. No support will be provided");
} else if (BuildMetadata.VM_VERSION != vm) {
ImGui.text("This build was designed for Java " + BuildMetadata.VM_VERSION + ", but you are using Java " + vm + ". No support will be provided");
} else {
try {
ImGui.text("For support, you can head to my ");
ImGui.sameLine();
@ -39,7 +42,7 @@ public class AboutWindow extends Window {
ImGui.sameLine();
ImGui.text(" space");
} catch (URISyntaxException e) {
Inceptum.showError("Could not complete task", e);
LauncherEnv.showError("Could not complete task", e);
}
}
}

View File

@ -1,25 +1,20 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window;
package io.gitlab.jfronny.inceptum.imgui.window;
import imgui.ImGui;
import imgui.flag.ImGuiTableFlags;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.model.curseforge.CurseforgeMod;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.inceptum.ModDescription;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthProjectType;
import io.gitlab.jfronny.inceptum.util.PathUtil;
import io.gitlab.jfronny.inceptum.util.mds.IWModDescription;
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.util.source.CurseforgeModSource;
import io.gitlab.jfronny.inceptum.util.source.ModDownload;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.util.source.ModrinthModSource;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthSearchResult;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthVersion;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.CurseforgeApi;
import io.gitlab.jfronny.inceptum.util.api.ModrinthApi;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.CurseforgeMod;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.model.modrinth.*;
import io.gitlab.jfronny.inceptum.launcher.system.source.*;
import io.gitlab.jfronny.inceptum.launcher.util.ModManager;
import io.gitlab.jfronny.inceptum.launcher.util.ModPath;
import io.gitlab.jfronny.inceptum.launcher.api.CurseforgeApi;
import io.gitlab.jfronny.inceptum.launcher.api.ModrinthApi;
import io.gitlab.jfronny.inceptum.launcher.system.mds.IWModDescription;
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
import java.io.IOException;
import java.net.URI;
@ -100,15 +95,14 @@ public class AddModWindow extends Window {
for (IWModDescription mdsMod : mds.getMods()) {
alreadyPresent = mdsMod.mod().isPresent()
&& mdsMod.mod().get().sources.keySet().stream()
.anyMatch(s -> s instanceof ModrinthModSource ms
&& ms.getModId().equals(mod.project_id));
.anyMatch(s -> s instanceof ModrinthModSource ms
&& ms.getModId().equals(mod.project_id));
if (alreadyPresent)
break;
}
if (alreadyPresent) {
ImGui.text("Installed");
}
else {
} else {
if (ImGui.button("Add##" + mod.project_id)) {
ModrinthVersion stable = null;
ModrinthVersion beta = null;
@ -127,15 +121,14 @@ public class AddModWindow extends Window {
if (stable != null) beta = stable;
if (beta != null) latest = beta;
if (latest == null) {
Inceptum.showError("No valid version could be identified for this mod", "No version found");
}
else {
LauncherEnv.showError("No valid version could be identified for this mod", "No version found");
} else {
ModrinthVersion finalLatest = latest;
new Thread(() -> {
try {
download(new ModrinthModSource(finalLatest.id), modsDir.resolve((mod.slug == null ? mod.project_id : mod.slug) + PathUtil.EXT_IMOD), mds).write();
ModManager.download(new ModrinthModSource(finalLatest.id), modsDir.resolve((mod.slug == null ? mod.project_id : mod.slug) + ModPath.EXT_IMOD), mds).write();
} catch (IOException e) {
Inceptum.showError("Could not download mod", e);
LauncherEnv.showError("Could not download mod", e);
}
}).start();
}
@ -185,8 +178,7 @@ public class AddModWindow extends Window {
}
if (alreadyPresent) {
ImGui.text("Installed");
}
else {
} else {
if (ImGui.button("Add##" + mod.id)) {
CurseforgeMod.LatestFileIndex latest = null;
for (CurseforgeMod.LatestFileIndex file : mod.latestFilesIndexes) {
@ -195,15 +187,14 @@ public class AddModWindow extends Window {
}
}
if (latest == null) {
Inceptum.showError("No valid version could be identified for this mod", "No version found");
}
else {
LauncherEnv.showError("No valid version could be identified for this mod", "No version found");
} else {
CurseforgeMod.LatestFileIndex finalLatest = latest;
new Thread(() -> {
try {
download(new CurseforgeModSource(mod.id, finalLatest.fileId), modsDir.resolve((mod.slug == null ? mod.id : mod.slug) + PathUtil.EXT_IMOD), mds).write();
ModManager.download(new CurseforgeModSource(mod.id, finalLatest.fileId), modsDir.resolve((mod.slug == null ? mod.id : mod.slug) + ModPath.EXT_IMOD), mds).write();
} catch (IOException e) {
Inceptum.showError("Could not download mod", e);
LauncherEnv.showError("Could not download mod", e);
}
}).start();
}
@ -224,30 +215,4 @@ public class AddModWindow extends Window {
Utils.LOGGER.error("Something went wrong while rendering an AddModWindow", e);
}
}
public static DownloadMeta download(ModSource ms, Path metaFile, ModsDirScanner mds) throws IOException {
for (IWModDescription value : mds.getMods()) {
if (value.mod().isEmpty()) continue;
for (ModSource source : value.mod().get().sources.keySet()) {
if (ms.equals(source)) {
return new DownloadMeta(new ModDownload(value.mod().get().sha1, value.mod().get().murmur2, value.path()), value.mod().get(), source, metaFile);
}
}
}
ModDownload md = ms.download();
ModDescription manifest = ModDescription.of(md.sha1(), md.murmur2(), ms, mds.getGameVersion());
for (ModSource dependency : ms.getDependencies(mds.getGameVersion())) {
DownloadMeta depMan = download(dependency, metaFile.getParent().resolve(dependency.getShortName() + PathUtil.EXT_IMOD), mds);
depMan.description.dependents.add(md.file().getFileName().toString());
manifest.dependencies.add(depMan.download.file().getFileName().toString());
depMan.write();
}
return new DownloadMeta(md, manifest, ms, metaFile);
}
public record DownloadMeta(ModDownload download, ModDescription description, ModSource source, Path metaFile) {
public void write() throws IOException {
Utils.writeObject(metaFile, description);
}
}
}

View File

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

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window;
package io.gitlab.jfronny.inceptum.imgui.window;
import imgui.ImGui;

View File

@ -1,30 +1,26 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window;
package io.gitlab.jfronny.inceptum.imgui.window;
import imgui.ImGui;
import imgui.flag.ImGuiWindowFlags;
import imgui.type.ImBoolean;
import imgui.type.ImInt;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.InstanceView;
import io.gitlab.jfronny.inceptum.util.ConfigHolder;
import io.gitlab.jfronny.inceptum.util.MapAppender;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
import io.gitlab.jfronny.inceptum.util.api.account.AuthInfo;
import io.gitlab.jfronny.inceptum.util.api.account.MicrosoftAccount;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.launcher.api.account.*;
import io.gitlab.jfronny.inceptum.imgui.GuiMain;
import io.gitlab.jfronny.inceptum.imgui.control.InstanceView;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Predicate;
public class MainWindow extends Window {
private final ImBoolean darkTheme = new ImBoolean(ConfigHolder.CONFIG.darkTheme);
private final ImBoolean debugTools = new ImBoolean(false);
private final ImInt accountIndex = new ImInt(AccountManager.getSelectedIndex());
public MainWindow() {
super("Inceptum");
}
@ -38,23 +34,23 @@ public class MainWindow extends Window {
public void draw() {
ImGui.beginMenuBar();
if (ImGui.beginMenu("File")) {
if (ImGui.menuItem("New Instance")) InceptumGui.open(new NewInstanceWindow());
if (ImGui.menuItem("New Instance")) GuiMain.open(new NewInstanceWindow());
if (ImGui.menuItem("Re-download resources")) {
try {
Utils.clearDirectory(MetaHolder.ASSETS_DIR);
Utils.clearDirectory(MetaHolder.LIBRARIES_DIR, path -> !path.startsWith(MetaHolder.LIBRARIES_DIR.resolve("io/gitlab/jfronny")));
Utils.clearDirectory(MetaHolder.NATIVES_DIR, path -> !path.endsWith("forceload"));
Utils.clearDirectory(MetaHolder.CACHE_DIR);
JFiles.clearDirectory(MetaHolder.ASSETS_DIR);
JFiles.clearDirectory(MetaHolder.LIBRARIES_DIR, path -> !path.startsWith(MetaHolder.LIBRARIES_DIR.resolve("io/gitlab/jfronny")));
JFiles.clearDirectory(MetaHolder.NATIVES_DIR, path -> !path.endsWith("forceload"));
JFiles.clearDirectory(MetaHolder.CACHE_DIR);
GuiUtil.reload();
} catch (IOException e) {
Inceptum.showError("Could not execute refresh task", e);
LauncherEnv.showError("Could not execute refresh task", e);
}
}
if (ImGui.menuItem("Exit Inceptum")) InceptumGui.exit();
if (ImGui.menuItem("Exit Inceptum")) GuiMain.exit();
ImGui.endMenu();
}
if (ImGui.beginMenu("Account")) {
if (ImGui.menuItem("New")) InceptumGui.open(new MicrosoftLoginWindow());
if (ImGui.menuItem("New")) GuiMain.open(new MicrosoftLoginWindow());
AuthInfo selected = AccountManager.getSelectedAccount();
List<MicrosoftAccount> accounts = AccountManager.getAccounts();
int accountsSize = accounts.size();
@ -76,13 +72,13 @@ public class MainWindow extends Window {
if (ImGui.checkbox("Dark Theme", darkTheme)) {
ConfigHolder.CONFIG.darkTheme = darkTheme.get();
ConfigHolder.saveConfig();
InceptumGui.applyTheme();
GuiMain.applyTheme();
}
ImGui.endMenu();
}
if (ImGui.beginMenu("Help")) {
if (ImGui.menuItem("About")) InceptumGui.open(new AboutWindow());
if (ImGui.menuItem("Log")) InceptumGui.open(new LogWindow(MapAppender.LOG));
if (ImGui.menuItem("About")) GuiMain.open(new AboutWindow());
if (ImGui.menuItem("Log")) GuiMain.open(new LogWindow(MapAppender.LOG));
ImGui.checkbox("Debug Tools", debugTools);
ImGui.endMenu();
}
@ -95,7 +91,7 @@ public class MainWindow extends Window {
List<Path> paths;
try {
if (!Files.exists(MetaHolder.INSTANCE_DIR)) Files.createDirectories(MetaHolder.INSTANCE_DIR);
paths = Utils.ls(MetaHolder.INSTANCE_DIR, (Predicate<Path>) Files::isDirectory);
paths = JFiles.list(MetaHolder.INSTANCE_DIR, Files::isDirectory);
} catch (IOException e) {
Utils.LOGGER.error("Could not list instances");
return;
@ -103,7 +99,6 @@ public class MainWindow extends Window {
if (paths.isEmpty()) {
ImGui.text("You have not yet created an instance");
ImGui.text("Use File->New Instance to do so");
}
else InstanceView.draw(paths);
} else InstanceView.draw(paths);
}
}

View File

@ -1,19 +1,18 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window;
package io.gitlab.jfronny.inceptum.imgui.window;
import com.sun.net.httpserver.*;
import imgui.*;
import com.sun.net.httpserver.HttpServer;
import imgui.ImGui;
import io.gitlab.jfronny.commons.serialize.Serializer;
import io.gitlab.jfronny.commons.serialize.SerializerHolder;
import io.gitlab.jfronny.commons.serialize.gson.api.*;
import io.gitlab.jfronny.inceptum.*;
import io.gitlab.jfronny.inceptum.model.microsoft.*;
import io.gitlab.jfronny.inceptum.util.*;
import io.gitlab.jfronny.inceptum.util.api.account.*;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.api.account.*;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.*;
import java.io.*;
import java.io.OutputStream;
import java.net.*;
import java.nio.charset.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Consumer;
public class MicrosoftLoginWindow extends Window {
private static HttpServer server;
@ -69,8 +68,7 @@ public class MicrosoftLoginWindow extends Window {
respStr = "Error logging in. Check console for more information";
Utils.LOGGER.error("Error logging into Microsoft account: " + URLDecoder
.decode(query.get("error_description"), StandardCharsets.UTF_8.toString()));
}
else if (query.containsKey("code")) {
} else if (query.containsKey("code")) {
try {
acquireAccessToken(query.get("code"));
respCode = 200;
@ -80,8 +78,7 @@ public class MicrosoftLoginWindow extends Window {
respCode = 500;
respStr = "Error logging in. Check console for more information";
}
}
else {
} else {
respCode = 400;
respStr = "Code is missing";
}
@ -133,11 +130,11 @@ public class MicrosoftLoginWindow extends Window {
Store store = MicrosoftAuthAPI.getMcEntitlements(loginResponse.accessToken);
Utils.LOGGER.info(SerializerHolder.getInstance().serialize(store));
Utils.LOGGER.info(Serializer.getInstance().serialize(store));
if (!(store.items.stream().anyMatch(i -> i.name.equalsIgnoreCase("product_minecraft"))
&& store.items.stream().anyMatch(i -> i.name.equalsIgnoreCase("game_minecraft")))) {
Inceptum.showError("This account doesn't have a valid purchase of Minecraft.\nPlease make sure you've bought the Java edition of Minecraft and then try again.", "Doesn't own Minecraft");
LauncherEnv.showError("This account doesn't have a valid purchase of Minecraft.\nPlease make sure you've bought the Java edition of Minecraft and then try again.", "Doesn't own Minecraft");
throw new Exception("Account does not own Minecraft");
}
@ -151,11 +148,10 @@ public class MicrosoftLoginWindow extends Window {
addAccount(oauthTokenResponse, xstsAuthResponse, loginResponse, profile);
close();
Inceptum.showInfo("The account \"" + profile.name + "\" was added successfully", "Account added");
LauncherEnv.showInfo("The account \"" + profile.name + "\" was added successfully", "Account added");
}
private void addAccount(OauthTokenResponse oauthTokenResponse, XboxLiveAuthResponse xstsAuthResponse,
LoginResponse loginResponse, Profile profile) throws Exception {
private void addAccount(OauthTokenResponse oauthTokenResponse, XboxLiveAuthResponse xstsAuthResponse, LoginResponse loginResponse, Profile profile) {
if (account != null || AccountManager.isAccountByName(loginResponse.username)) {
MicrosoftAccount account = (MicrosoftAccount) AccountManager.getAccountByName(loginResponse.username);
@ -164,18 +160,22 @@ public class MicrosoftLoginWindow extends Window {
}
// if forced to relogin, then make sure they logged into correct account
if (this.account != null && account.accountId != this.account.accountId) {
Inceptum.showError("Logged into incorrect account. Please login again on the Accounts tab", "Incorrect account");
if (this.account != null && !Objects.equals(account.accountId, this.account.accountId)) {
LauncherEnv.showError("Logged into incorrect account. Please login again on the Accounts tab", "Incorrect account");
return;
}
account.update(oauthTokenResponse, xstsAuthResponse, loginResponse, profile);
AccountManager.saveAccounts();
} else {
MicrosoftAccount account = new MicrosoftAccount(oauthTokenResponse, xstsAuthResponse, loginResponse,
profile);
MicrosoftAccount account = new MicrosoftAccount(oauthTokenResponse, xstsAuthResponse, loginResponse, profile);
AccountManager.addAccount(account);
}
}
@Override
public void close() {
super.close();
stopServer();
}
}

View File

@ -1,15 +1,17 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window;
package io.gitlab.jfronny.inceptum.imgui.window;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.InstanceManageControls;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.util.install.Steps;
import io.gitlab.jfronny.inceptum.common.R;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.imgui.control.InstanceManageControls;
import io.gitlab.jfronny.inceptum.launcher.system.install.SetupStepInfo;
import io.gitlab.jfronny.inceptum.launcher.system.install.Steps;
import java.io.IOException;
public class NewInstanceWindow extends Window {
private final InstanceManageControls imc = new InstanceManageControls(null, null);
public NewInstanceWindow() {
super("New Instance");
}
@ -19,7 +21,7 @@ public class NewInstanceWindow extends Window {
if (ImGui.beginTabBar("NewInstanceBar")) {
if (ImGui.beginTabItem("New")) {
imc.snapshotsBox();
imc.versionBox(ver -> {});
imc.versionBox(R::nop);
imc.nameBox("OK", name -> {
try {
GuiUtil.createInstance(new SetupStepInfo(imc.getVersionInfo(),

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window;
package io.gitlab.jfronny.inceptum.imgui.window;
import imgui.flag.ImGuiWindowFlags;
import imgui.type.ImBoolean;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.imgui.GuiMain;
import java.io.Closeable;
@ -17,6 +17,7 @@ public abstract class Window implements Closeable {
public void preFirstDraw() {
}
public abstract void draw();
public String getName() {
@ -27,7 +28,7 @@ public abstract class Window implements Closeable {
public void close() {
state = State.Closed;
openState.set(false);
InceptumGui.WINDOWS.remove(this);
GuiMain.WINDOWS.remove(this);
}
public boolean isNew() {

View File

@ -1,8 +1,8 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.dialog;
package io.gitlab.jfronny.inceptum.imgui.window.dialog;
import imgui.ImGui;
import imgui.flag.ImGuiWindowFlags;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
import io.gitlab.jfronny.inceptum.imgui.window.Window;
public class AlertWindow extends Window {
private final String message;
@ -47,8 +47,7 @@ public class AlertWindow extends Window {
super.close();
if (success) {
if (onOk != null) onOk.run();
}
else {
} else {
if (onCancel != null) onCancel.run();
}
}

View File

@ -1,10 +1,10 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.dialog;
package io.gitlab.jfronny.inceptum.imgui.window.dialog;
import imgui.ImGui;
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.imgui.window.Window;
import io.gitlab.jfronny.inceptum.launcher.util.ProcessState;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.atomic.AtomicBoolean;
@ -25,7 +25,7 @@ public class ProcessStateWatcherWindow extends Window {
if (canceled.get() && cancel != null) cancel.run();
finished = true;
} catch (Throwable e) {
Inceptum.showError(errorMessage, e);
LauncherEnv.showError(errorMessage, e);
}
close();
}).start();
@ -48,8 +48,7 @@ public class ProcessStateWatcherWindow extends Window {
public void close() {
if (finished) {
super.close();
}
else if (cancel != null) {
} else if (cancel != null) {
canceled.set(true);
}
}

View File

@ -1,9 +1,9 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.dialog;
package io.gitlab.jfronny.inceptum.imgui.window.dialog;
import imgui.ImGui;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
import io.gitlab.jfronny.inceptum.imgui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.imgui.window.Window;
import java.util.function.Consumer;
@ -44,8 +44,7 @@ public class TextBoxWindow extends Window {
super.close();
if (success) {
if (onOk != null) onOk.accept(selected.get());
}
else {
} else {
if (onCancel != null) onCancel.run();
}
}

View File

@ -1,10 +1,10 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
package io.gitlab.jfronny.inceptum.imgui.window.edit;
import imgui.ImGui;
import imgui.type.ImString;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.imgui.control.Tab;
import io.gitlab.jfronny.inceptum.imgui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import java.util.LinkedList;
import java.util.List;

View File

@ -1,14 +1,15 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
package io.gitlab.jfronny.inceptum.imgui.window.edit;
import imgui.ImGui;
import io.gitlab.jfronny.commons.throwable.ThrowingBiConsumer;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.dialog.ProcessStateWatcherWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.window.dialog.TextBoxWindow;
import io.gitlab.jfronny.inceptum.util.InstanceExporter;
import io.gitlab.jfronny.inceptum.util.ProcessState;
import io.gitlab.jfronny.inceptum.common.R;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.imgui.GuiMain;
import io.gitlab.jfronny.inceptum.imgui.control.Tab;
import io.gitlab.jfronny.inceptum.imgui.window.dialog.ProcessStateWatcherWindow;
import io.gitlab.jfronny.inceptum.imgui.window.dialog.TextBoxWindow;
import io.gitlab.jfronny.inceptum.launcher.system.export.InstanceExporter;
import io.gitlab.jfronny.inceptum.launcher.util.ProcessState;
import org.lwjgl.PointerBuffer;
import org.lwjgl.system.MemoryStack;
import org.lwjgl.util.tinyfd.TinyFileDialogs;
@ -31,18 +32,17 @@ public class ExportTab extends Tab {
if (window.mds.isComplete()) {
AtomicReference<String> cfVersion = new AtomicReference<>();
exportVariant("CurseForge", "zip", it -> {
InceptumGui.WINDOWS.add(new TextBoxWindow("Version", "Please enter the version to list in the modpack file", "1.0", version -> {
GuiMain.WINDOWS.add(new TextBoxWindow("Version", "Please enter the version to list in the modpack file", "1.0", version -> {
cfVersion.set(version);
it.run();
}, () -> {}));
}, R::nop));
}, (state, exportPath) -> {
InstanceExporter.exportCurseZip(state, window.path, window.instance, window.mds, exportPath, cfVersion.get());
});
exportVariant("MultiMC", "zip", Runnable::run, (state, exportPath) -> {
InstanceExporter.exportMultiMCZip(state, window.path, window.instance, window.mds, exportPath);
});
}
else {
} else {
ImGui.text("The mods directory scan must be completed.\nThe progress for this can be observed in the mods tab");
}
}
@ -57,10 +57,10 @@ public class ExportTab extends Tab {
String p = TinyFileDialogs.tinyfd_saveFileDialog("Export Pack", "", aFilterPatterns, name + " packs (*." + packExt + ")");
if (p != null) {
ProcessState state = new ProcessState(InstanceExporter.STEP_COUNT, "Initializing...");
InceptumGui.open(new ProcessStateWatcherWindow("Exporting", "Could not export pack", state, cToken -> {
GuiMain.open(new ProcessStateWatcherWindow("Exporting", "Could not export pack", state, cToken -> {
Path exportPath = Paths.get(p);
export.accept(state, exportPath);
Inceptum.showInfo(window.path.getFileName().toString() + " has been successfully exported to " + exportPath, "Successfully exported");
LauncherEnv.showInfo(window.path.getFileName().toString() + " has been successfully exported to " + exportPath, "Successfully exported");
}, null));
}
}

View File

@ -1,16 +1,16 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
package io.gitlab.jfronny.inceptum.imgui.window.edit;
import imgui.ImGui;
import imgui.type.ImBoolean;
import imgui.type.ImString;
import io.gitlab.jfronny.commons.OSUtils;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.InstanceManageControls;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.imgui.GuiMain;
import io.gitlab.jfronny.inceptum.imgui.control.InstanceManageControls;
import io.gitlab.jfronny.inceptum.imgui.control.Tab;
import io.gitlab.jfronny.inceptum.imgui.window.GuiUtil;
import java.io.IOException;
import java.nio.file.Files;
@ -38,10 +38,10 @@ public class GeneralTab extends Tab {
try {
Path newPath = MetaHolder.INSTANCE_DIR.resolve(name);
Files.move(window.path, newPath);
InceptumGui.open(new InstanceEditWindow(newPath, window.instance));
GuiMain.open(new InstanceEditWindow(newPath, window.instance));
window.close();
} catch (IOException e) {
Inceptum.showError("Could not rename", e);
LauncherEnv.showError("Could not rename", e);
}
});
imc.snapshotsBox();
@ -50,14 +50,15 @@ public class GeneralTab extends Tab {
window.instance.version = ver;
window.save();
});
if (ImGui.button("Delete")) Inceptum.showOkCancel("This instance will be removed forever (a long time)", "Are you sure?", () -> {
try {
Utils.deleteRecursive(window.path);
} catch (IOException e) {
Inceptum.showError("Could not delete the instance", e);
}
window.close();
}, () -> {});
if (ImGui.button("Delete"))
LauncherEnv.showOkCancel("This instance will be removed forever (a long time)", "Are you sure?", () -> {
try {
JFiles.deleteRecursive(window.path);
} catch (IOException e) {
LauncherEnv.showError("Could not delete the instance", e);
}
window.close();
}, R::nop);
if (ImGui.checkbox("Custom Java", customJava)) {
if (customJava.get()) {
window.instance.java = OSUtils.getJvmBinary();

View File

@ -1,13 +1,14 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
package io.gitlab.jfronny.inceptum.imgui.window.edit;
import imgui.ImGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.frontend.gui.window.Window;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.util.InstanceLock;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.imgui.control.Tab;
import io.gitlab.jfronny.inceptum.imgui.window.GuiUtil;
import io.gitlab.jfronny.inceptum.imgui.window.Window;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.util.InstanceLock;
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
import java.io.IOException;
import java.nio.file.Path;
@ -60,7 +61,7 @@ public class InstanceEditWindow extends Window {
protected void save() {
try {
Utils.writeObject(path.resolve("instance.json"), instance);
JFiles.writeObject(path.resolve("instance.json"), instance);
} catch (IOException e) {
Utils.LOGGER.error("Could not write instance config", e);
}

View File

@ -1,23 +1,21 @@
package io.gitlab.jfronny.inceptum.frontend.gui.window.edit;
package io.gitlab.jfronny.inceptum.imgui.window.edit;
import imgui.ImGui;
import imgui.type.ImBoolean;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.gui.control.Tab;
import io.gitlab.jfronny.inceptum.frontend.gui.window.AddModWindow;
import io.gitlab.jfronny.inceptum.util.ModManager;
import io.gitlab.jfronny.inceptum.util.PathUtil;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.util.mds.IWModDescription;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.imgui.GuiMain;
import io.gitlab.jfronny.inceptum.imgui.control.Tab;
import io.gitlab.jfronny.inceptum.imgui.window.AddModWindow;
import io.gitlab.jfronny.inceptum.launcher.util.ModManager;
import io.gitlab.jfronny.inceptum.launcher.util.ModPath;
import io.gitlab.jfronny.inceptum.launcher.system.mds.IWModDescription;
import io.gitlab.jfronny.inceptum.launcher.system.source.ModSource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
public class ModsTab extends Tab {
private final InstanceEditWindow window;
@ -41,7 +39,7 @@ public class ModsTab extends Tab {
}
ImGui.beginChild("mods select", 200, 0);
if (ImGui.button("Add")) {
InceptumGui.WINDOWS.add(new AddModWindow(window.path.resolve("mods"), window.instance, window.mds));
GuiMain.WINDOWS.add(new AddModWindow(window.path.resolve("mods"), window.instance, window.mds));
}
ImGui.sameLine();
if (Files.exists(window.path.resolve("mods")) && ImGui.button("Show")) {
@ -84,15 +82,15 @@ public class ModsTab extends Tab {
}
}
if (filterUpdates.get() && !updatesFound) continue;
boolean wasEnabled = PathUtil.isEnabled(mod.path());
boolean wasEnabled = ModPath.isEnabled(mod.path());
if (ImGui.checkbox("##" + mod.getName(), wasEnabled)) {
Path newSel = PathUtil.toggle(mod.path());
Path newSel = ModPath.toggle(mod.path());
try {
Files.move(mod.path(), newSel);
if (mod.path().equals(selected)) selected = newSel;
mod = new IWModDescription(newSel, mod);
} catch (IOException e) {
Inceptum.showError("Could not change disabled state", e);
LauncherEnv.showError("Could not change disabled state", e);
}
}
ImGui.sameLine();
@ -127,8 +125,8 @@ public class ModsTab extends Tab {
ImGui.sameLine();
if (ImGui.button("Update to " + ms.get().getVersion())) {
try {
Path imodPath = md.imod().isPresent() ? md.imod().get() : window.path.resolve("mods").resolve(ms.get().getShortName() + PathUtil.EXT_IMOD);
AddModWindow.DownloadMeta dm = AddModWindow.download(ms.get(), imodPath, window.mds);
Path imodPath = md.imod().isPresent() ? md.imod().get() : window.path.resolve("mods").resolve(ms.get().getShortName() + ModPath.EXT_IMOD);
ModManager.DownloadMeta dm = ModManager.download(ms.get(), imodPath, window.mds);
Files.delete(md.path());
if (md.imod().isPresent() && Files.exists(md.imod().get()))
Files.delete(md.imod().get());
@ -136,7 +134,7 @@ public class ModsTab extends Tab {
selected = imodPath;
window.mds.invalidate(imodPath);
} catch (IOException e) {
Inceptum.showError("Update failed", e);
LauncherEnv.showError("Update failed", e);
}
}
}
@ -145,18 +143,17 @@ public class ModsTab extends Tab {
}
if (ImGui.button("Delete")) {
if (md.mod().isPresent() && !md.mod().get().dependents.isEmpty())
Inceptum.showError("This mod still has the following dependent mods installed: " + String.join(", ", md.mod().get().dependents), "Dependents present");
LauncherEnv.showError("This mod still has the following dependent mods installed: " + String.join(", ", md.mod().get().dependents), "Dependents present");
else {
try {
delete(md);
} catch (IOException e) {
Inceptum.showError("Couldn't delete the file", e);
LauncherEnv.showError("Couldn't delete the file", e);
}
selected = null;
}
}
}
else {
} else {
ImGui.text("This mod has not yet been scanned, please be patient");
}
ImGui.endGroup();

View File

@ -0,0 +1,20 @@
plugins {
id("inceptum.application-standalone-conventions")
}
application {
mainClass.set("io.gitlab.jfronny.inceptum.Inceptum")
}
dependencies {
implementation(project(":launcher"))
implementation(project(":launcher-cli"))
implementation(project(":launcher-imgui"))
}
tasks.shadowJar {
archiveClassifier.set(rootProject.extra["flavorProp"] as String)
exclude("about.html")
exclude("plugin.properties")
exclude("META-INF/**")
}

View File

@ -0,0 +1,21 @@
package io.gitlab.jfronny.inceptum;
import io.gitlab.jfronny.inceptum.cli.Command;
import io.gitlab.jfronny.inceptum.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.imgui.GuiMain;
public class GuiCommand extends Command {
public GuiCommand() {
super("Displays the Inceptum UI", "", "gui", "show");
}
@Override
public void invoke(CommandArgs args) {
GuiMain.main(args.wrapped);
}
@Override
public boolean enableLog() {
return true;
}
}

View File

@ -0,0 +1,14 @@
package io.gitlab.jfronny.inceptum;
import io.gitlab.jfronny.inceptum.cli.CliMain;
public class Inceptum {
private static final GuiCommand GUI_COMMAND = new GuiCommand();
public static void main(String[] args) throws Exception {
CliMain.KNOWN_COMMANDS.add(1, GUI_COMMAND);
CliMain.KNOWN_COMMANDS.add(new UpdateCheckCommand());
CliMain.DEFAULT = GUI_COMMAND;
CliMain.main(args);
}
}

View File

@ -0,0 +1,51 @@
package io.gitlab.jfronny.inceptum;
import io.gitlab.jfronny.inceptum.cli.Command;
import io.gitlab.jfronny.inceptum.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateInfo;
import io.gitlab.jfronny.inceptum.imgui.ImBuildMetadata;
import io.gitlab.jfronny.inceptum.launcher.Updater;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;
public class UpdateCheckCommand extends Command {
private final boolean install;
public UpdateCheckCommand() {
super("Checks for inceptum updates", "", List.of("update"), List.of(
new UpdateCheckCommand("Automatically install updates", "install", true)
));
install = false;
}
private UpdateCheckCommand(String help, String name, boolean install) {
super(help, "", name);
this.install = install;
}
@Override
protected void invoke(CommandArgs args) {
if (install && !args.wrapped) {
Utils.LOGGER.error("Automatic updates are not supported without the wrapper");
return;
}
UpdateInfo updateUrl = Updater.getUpdate(ImBuildMetadata.FLAVOR);
if (updateUrl == null) {
Utils.LOGGER.info("No update was found");
} else {
if (install) {
Utils.LOGGER.info("Installing from " + updateUrl);
try {
Updater.update(updateUrl, false);
} catch (IOException | URISyntaxException e) {
Utils.LOGGER.error("Could not download update", e);
}
} else {
Utils.LOGGER.info("An update was found: " + updateUrl);
}
}
}
}

View File

@ -1,73 +1,8 @@
plugins {
java
application
`maven-publish`
id("com.github.johnrengelman.shadow") version "7.1.2"
}
application {
mainClass.set("io.gitlab.jfronny.inceptum.Inceptum")
}
repositories {
mavenCentral()
maven {
setUrl("https://gitlab.com/api/v4/projects/35745143/packages/maven")
}
id("inceptum.library-conventions")
}
dependencies {
val flavor: String by rootProject.extra
val lwjglVersion: String by rootProject.extra
val imguiVersion: String by rootProject.extra
implementation(project(":common"))
implementation(platform("org.lwjgl:lwjgl-bom:$lwjglVersion"))
api(project(":common"))
compileOnly("org.jetbrains:annotations:23.0.0")
arrayOf("", "-opengl", "-glfw", "-tinyfd").forEach {
implementation("org.lwjgl:lwjgl$it:$lwjglVersion")
if (flavor == "windows" || flavor == "fat") implementation("org.lwjgl:lwjgl$it::natives-windows")
if (flavor == "linux" || flavor == "fat") implementation("org.lwjgl:lwjgl$it::natives-linux")
if (flavor == "macos" || flavor == "fat") implementation("org.lwjgl:lwjgl$it::natives-macos")
}
implementation("io.github.spair:imgui-java-binding:$imguiVersion") // https://github.com/SpaiR/imgui-java
implementation ("io.github.spair:imgui-java-lwjgl3:$imguiVersion")
if (flavor == "windows" || flavor == "fat") implementation("io.github.spair:imgui-java-natives-windows:$imguiVersion")
if (flavor == "linux" || flavor == "fat") implementation("io.github.spair:imgui-java-natives-linux:$imguiVersion")
if (flavor == "macos" || flavor == "fat") implementation("io.github.spair:imgui-java-natives-macos:$imguiVersion")
}
tasks.shadowJar {
archiveClassifier.set(rootProject.extra["flavorProp"] as String)
exclude("about.html")
exclude("plugin.properties")
exclude("META-INF/**")
}
publishing {
publications {
create<MavenPublication>("mavenJava") {
artifact(tasks.shadowJar) {
builtBy(tasks.shadowJar)
}
}
}
if (rootProject.extra["isPublic"] == true) {
repositories.maven {
url = uri("https://gitlab.com/api/v4/projects/30862253/packages/maven")
name = "gitlab"
credentials(HttpHeaderCredentials::class) {
name = "Job-Token"
value = System.getenv()["CI_JOB_TOKEN"]
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
repositories.mavenLocal()
}

View File

@ -1,106 +0,0 @@
package io.gitlab.jfronny.inceptum;
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandResolution;
import io.gitlab.jfronny.inceptum.frontend.cli.Commands;
import io.gitlab.jfronny.inceptum.frontend.gui.window.dialog.AlertWindow;
import io.gitlab.jfronny.inceptum.frontend.gui.window.dialog.TextBoxWindow;
import io.gitlab.jfronny.inceptum.gson.*;
import io.gitlab.jfronny.inceptum.util.*;
import io.gitlab.jfronny.inceptum.util.source.ModSource;
import io.gitlab.jfronny.inceptum.model.microsoft.OauthTokenResponse;
import io.gitlab.jfronny.inceptum.model.mojang.MinecraftArgument;
import io.gitlab.jfronny.inceptum.model.mojang.Rules;
import io.gitlab.jfronny.inceptum.util.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.util.api.McApi;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Scanner;
import java.util.function.Consumer;
public class Inceptum {
public static boolean IS_GUI;
public static void main(String[] args) throws Exception {
if (Utils.class.getClassLoader() != Inceptum.class.getClassLoader()) {
throw new IllegalStateException("Mismatching classloader between two classes. Something is wrong here");
}
CommandResolution command = Commands.resolve(args, false);
if (command.command().enableLog()) {
Utils.LOGGER.info("Launching Inceptum v" + MetaHolder.VERSION.version + " (" + MetaHolder.VERSION.flavor + ")");
Utils.LOGGER.info("Loading from " + MetaHolder.BASE_PATH);
}
GsonHolder.registerTypeAdapter(MinecraftArgument.class, new MinecraftArgumentDeserializer());
GsonHolder.registerTypeAdapter(Rules.class, new RulesDeserializer());
GsonHolder.registerTypeAdapter(OauthTokenResponse.class, new OauthTokenResponseDeserializer());
GsonHolder.registerTypeAdapter(ModSource.class, new ModSourceTypeAdapter());
GsonHolder.registerTypeAdapter(ModSourceMapDeserializer.modSourceMapType, new ModSourceMapDeserializer());
InceptumEnvironmentInitializer.initialize();
if (!Files.exists(MetaHolder.CACHE_DIR)) Files.createDirectories(MetaHolder.CACHE_DIR);
try {
McApi.getVersions();
Utils.clearDirectory(MetaHolder.CACHE_DIR);
}
catch (IOException e) {
Utils.LOGGER.error("Could not connect to the internet");
}
if (!Files.exists(MetaHolder.INSTANCE_DIR)) Files.createDirectories(MetaHolder.INSTANCE_DIR);
if (!Files.exists(MetaHolder.ASSETS_DIR)) Files.createDirectories(MetaHolder.ASSETS_DIR);
if (!Files.exists(MetaHolder.LIBRARIES_DIR)) Files.createDirectories(MetaHolder.LIBRARIES_DIR);
if (Files.exists(MetaHolder.FORCE_LOAD_PATH)) {
Utils.LOGGER.info("Force-Loading libraries:");
Utils.ls(MetaHolder.FORCE_LOAD_PATH, path -> {
Utils.LOGGER.info("Loading " + path);
try {
System.load(path.toAbsolutePath().toString());
}
catch (UnsatisfiedLinkError le) {
Utils.LOGGER.error("Could not load library", le);
}
});
}
command.invoke();
ModsDirScanner.closeAll();
}
public static void showError(String message, String title) {
Utils.LOGGER.error(message);
if (IS_GUI) InceptumGui.WINDOWS.add(new AlertWindow(title, message));
}
public static void showError(String message, Throwable t) {
Utils.LOGGER.error(message, t);
if (IS_GUI) InceptumGui.WINDOWS.add(new AlertWindow(message, t.toString()));
}
public static void showInfo(String message, String title) {
Utils.LOGGER.info(message);
if (IS_GUI) InceptumGui.WINDOWS.add(new AlertWindow(title, message));
}
public static void showOkCancel(String message, String title, Runnable ok, Runnable cancel) {
showOkCancel(message, title, ok, cancel, false);
}
public static void showOkCancel(String message, String title, Runnable ok, Runnable cancel, boolean defaultCancel) {
Utils.LOGGER.info(message);
if (IS_GUI) InceptumGui.WINDOWS.add(new AlertWindow(title, message, ok, cancel));
else if (!defaultCancel) ok.run();
}
public static void getInput(String prompt, String details, String defaultValue, Consumer<String> ok, Runnable cancel) throws IOException {
if (IS_GUI) InceptumGui.WINDOWS.add(new TextBoxWindow(prompt, details, defaultValue, ok, cancel));
else {
Scanner scanner = new Scanner(System.in);
System.out.println(prompt);
System.out.print("> ");
ok.accept(scanner.nextLine());
}
}
}

View File

@ -1,38 +0,0 @@
package io.gitlab.jfronny.inceptum.frontend.cli;
import io.gitlab.jfronny.inceptum.frontend.cli.commands.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Commands {
private static final GuiCommand GUI_COMMAND = new GuiCommand();
public static final Command COMMANDS_ROOT = new Command("Root command", "<command>", List.of(), List.of(
new HelpCommand(),
GUI_COMMAND,
new LaunchCommand(),
new ListCommand(),
new ModCommand(),
new ExportCommand(),
new UpdateCheckCommand(),
new JvmStateCommand(),
new BatchCommand(),
new WrapperCommand()
)) {
@Override
protected void invoke(CommandArgs args) {
throw new RuntimeException("Could not find command: " + args.get(0));
}
@Override
public CommandResolution resolve(CommandArgs args) {
if (args.length == 0) return new CommandResolution(GUI_COMMAND, args, new ArrayList<>());
return super.resolve(args);
}
};
public static CommandResolution resolve(String[] args, boolean wrapped) {
return COMMANDS_ROOT.resolve(new CommandArgs(Arrays.asList(args), wrapped));
}
}

View File

@ -1,53 +0,0 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
import io.gitlab.jfronny.inceptum.Inceptum;
import io.gitlab.jfronny.inceptum.InceptumGui;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.UpdateInfo;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.frontend.gui.window.MainWindow;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
public class GuiCommand extends Command {
public GuiCommand() {
super("Displays the Inceptum UI", "", "gui", "show");
}
@Override
public void invoke(CommandArgs args) {
Inceptum.IS_GUI = true;
UpdateInfo update = UpdateCheckCommand.getUpdate();
InceptumGui.main(args, () -> {
if (update == null) {
InceptumGui.WINDOWS.add(new MainWindow());
} else if (args.wrapped) {
Inceptum.showOkCancel("An update was found. Should it be installed automatically?", "Update found", () -> {
try {
UpdateCheckCommand.update(update, true);
InceptumGui.exit();
} catch (IOException | URISyntaxException e) {
Inceptum.showError("Could not download update", e);
}
}, () -> InceptumGui.WINDOWS.add(new MainWindow()));
} else {
Inceptum.showOkCancel("An update was found. Automatic installs are not supported without the wrapper but you can download it nonetheless", "Update found", () -> {
try {
Utils.openWebBrowser(new URI(update.url()));
InceptumGui.exit();
} catch (URISyntaxException e) {
Inceptum.showError("Could not download update", e);
}
}, () -> InceptumGui.WINDOWS.add(new MainWindow()));
}
});
}
@Override
public boolean enableLog() {
return true;
}
}

View File

@ -1,83 +0,0 @@
package io.gitlab.jfronny.inceptum.frontend.cli.commands;
import io.gitlab.jfronny.commons.OSUtils;
import io.gitlab.jfronny.inceptum.frontend.cli.Command;
import io.gitlab.jfronny.inceptum.frontend.cli.CommandArgs;
import io.gitlab.jfronny.inceptum.model.inceptum.UpdateInfo;
import io.gitlab.jfronny.inceptum.util.*;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class UpdateCheckCommand extends Command {
private final boolean install;
public UpdateCheckCommand() {
super("Checks for inceptum updates", "", List.of("update"), List.of(
new UpdateCheckCommand("Automatically install updates", "install", true)
));
install = false;
}
private UpdateCheckCommand(String help, String name, boolean install) {
super(help, "", name);
this.install = install;
}
@Override
protected void invoke(CommandArgs args) {
if (install && !args.wrapped) {
Utils.LOGGER.error("Automatic updates are not supported without the wrapper");
return;
}
UpdateInfo updateUrl = getUpdate();
if (updateUrl == null) {
Utils.LOGGER.info("No update was found");
} else {
if (install) {
Utils.LOGGER.info("Installing from " + updateUrl);
try {
update(updateUrl, false);
} catch (IOException | URISyntaxException e) {
Utils.LOGGER.error("Could not download update", e);
}
}
else {
Utils.LOGGER.info("An update was found: " + updateUrl);
}
}
}
public static UpdateInfo getUpdate() {
return UpdateChecker.check(ConfigHolder.CONFIG.channel, MetaHolder.VERSION.version, MetaHolder.VERSION.flavor, channel -> {
Utils.LOGGER.error("No stable version was found, switching to experimental channel");
ConfigHolder.CONFIG.channel = channel;
ConfigHolder.saveConfig();
});
}
public static void update(UpdateInfo source, boolean relaunch) throws IOException, URISyntaxException {
Utils.LOGGER.info("Downloading " + source.url());
Path jarPath = MetaHolder.LIBRARIES_DIR.resolve("io/gitlab/jfronny/inceptum/Inceptum")
.resolve(source.newVersion().toString())
.resolve("Inceptum-" + source.newVersion() + '-' + OSUtils.TYPE.getMojName() + ".jar")
.toAbsolutePath();
Files.createDirectories(jarPath.getParent());
Utils.downloadFile(source.url(), source.sha1(), jarPath);
if (relaunch) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
new ProcessBuilder(OSUtils.getJvmBinary(),
"-jar",
jarPath.toString())
.inheritIO()
.start();
} catch (IOException e) {
Utils.LOGGER.error("Could not relaunch", e);
}
}));
}
}
}

View File

@ -0,0 +1,105 @@
package io.gitlab.jfronny.inceptum.launcher;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.commons.serialize.gson.api.GsonHolder;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.launcher.api.McApi;
import io.gitlab.jfronny.inceptum.launcher.api.account.MicrosoftAccount;
import io.gitlab.jfronny.inceptum.launcher.gson.*;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.OauthTokenResponse;
import io.gitlab.jfronny.inceptum.launcher.model.mojang.MinecraftArgument;
import io.gitlab.jfronny.inceptum.launcher.model.mojang.Rules;
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.launcher.system.source.ModSource;
import java.io.IOException;
import java.nio.file.Files;
import java.util.function.Consumer;
public class LauncherEnv {
private static EnvBackend backend;
public static void checkClassLoaderState() {
if (Utils.class.getClassLoader() != LauncherEnv.class.getClassLoader()) {
throw new IllegalStateException("Mismatching classloader between two classes. Something is wrong here");
}
}
public static void initialize(EnvBackend backend) throws IOException {
LauncherEnv.backend = backend;
GsonHolder.registerTypeAdapter(MinecraftArgument.class, new MinecraftArgumentDeserializer());
GsonHolder.registerTypeAdapter(Rules.class, new RulesDeserializer());
GsonHolder.registerTypeAdapter(OauthTokenResponse.class, new OauthTokenResponseDeserializer());
GsonHolder.registerTypeAdapter(ModSource.class, new ModSourceTypeAdapter());
GsonHolder.registerTypeAdapter(ModSourceMapDeserializer.modSourceMapType, new ModSourceMapDeserializer());
InceptumEnvironmentInitializer.initialize();
if (!Files.exists(MetaHolder.CACHE_DIR)) Files.createDirectories(MetaHolder.CACHE_DIR);
try {
McApi.getVersions();
JFiles.clearDirectory(MetaHolder.CACHE_DIR);
} catch (IOException e) {
Utils.LOGGER.error("Could not connect to the internet");
}
if (!Files.exists(MetaHolder.INSTANCE_DIR)) Files.createDirectories(MetaHolder.INSTANCE_DIR);
if (!Files.exists(MetaHolder.ASSETS_DIR)) Files.createDirectories(MetaHolder.ASSETS_DIR);
if (!Files.exists(MetaHolder.LIBRARIES_DIR)) Files.createDirectories(MetaHolder.LIBRARIES_DIR);
if (Files.exists(MetaHolder.FORCE_LOAD_PATH)) {
Utils.LOGGER.info("Force-Loading libraries:");
JFiles.listTo(MetaHolder.FORCE_LOAD_PATH, path -> {
Utils.LOGGER.info("Loading " + path);
try {
System.load(path.toAbsolutePath().toString());
} catch (UnsatisfiedLinkError le) {
Utils.LOGGER.error("Could not load library", le);
}
});
}
}
public static void terminate() {
ModsDirScanner.closeAll();
}
public static void showError(String message, String title) {
backend.showError(message, title);
}
public static void showError(String message, Throwable t) {
backend.showError(message, t);
}
public static void showInfo(String message, String title) {
backend.showInfo(message, title);
}
public static void showOkCancel(String message, String title, Runnable ok, Runnable cancel) {
backend.showOkCancel(message, title, ok, cancel);
}
public static void showOkCancel(String message, String title, Runnable ok, Runnable cancel, boolean defaultCancel) {
backend.showOkCancel(message, title, ok, cancel, defaultCancel);
}
public static void getInput(String prompt, String details, String defaultValue, Consumer<String> ok, Runnable cancel) throws IOException {
backend.getInput(prompt, details, defaultValue, ok, cancel);
}
public static void showLoginRefreshPrompt(MicrosoftAccount account) {
backend.showLoginRefreshPrompt(account);
}
public interface EnvBackend {
void showError(String message, String title);
void showError(String message, Throwable t);
void showInfo(String message, String title);
default void showOkCancel(String message, String title, Runnable ok, Runnable cancel) {
showOkCancel(message, title, ok, cancel, false);
}
void showOkCancel(String message, String title, Runnable ok, Runnable cancel, boolean defaultCancel);
void getInput(String prompt, String details, String defaultValue, Consumer<String> ok, Runnable cancel) throws IOException;
void showLoginRefreshPrompt(MicrosoftAccount account);
}
}

View File

@ -0,0 +1,44 @@
package io.gitlab.jfronny.inceptum.launcher;
import io.gitlab.jfronny.commons.OSUtils;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.common.model.inceptum.UpdateInfo;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
public class Updater {
public static UpdateInfo getUpdate(String flavor) {
return UpdateChecker.check(ConfigHolder.CONFIG.channel, BuildMetadata.VERSION, flavor, channel -> {
Utils.LOGGER.error("No stable version was found, switching to experimental channel");
ConfigHolder.CONFIG.channel = channel;
ConfigHolder.saveConfig();
});
}
//TODO (possibly) rework for new structure
public static void update(UpdateInfo source, boolean relaunch) throws IOException, URISyntaxException {
Utils.LOGGER.info("Downloading " + source.url());
Path jarPath = MetaHolder.LIBRARIES_DIR.resolve("io/gitlab/jfronny/inceptum/Inceptum")
.resolve(source.newVersion().toString())
.resolve("Inceptum-" + source.newVersion() + '-' + OSUtils.TYPE.getMojName() + ".jar")
.toAbsolutePath();
Files.createDirectories(jarPath.getParent());
Net.downloadFile(source.url(), source.sha1(), jarPath);
if (relaunch) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
new ProcessBuilder(OSUtils.getJvmBinary(),
"-jar",
jarPath.toString())
.inheritIO()
.start();
} catch (IOException e) {
Utils.LOGGER.error("Could not relaunch", e);
}
}));
}
}
}

View File

@ -1,19 +1,21 @@
package io.gitlab.jfronny.inceptum.util.api;
package io.gitlab.jfronny.inceptum.launcher.api;
import io.gitlab.jfronny.commons.*;
import io.gitlab.jfronny.inceptum.model.curseforge.*;
import io.gitlab.jfronny.inceptum.model.curseforge.response.*;
import io.gitlab.jfronny.inceptum.util.*;
import io.gitlab.jfronny.commons.HttpUtils;
import io.gitlab.jfronny.inceptum.common.Net;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.CurseforgeFile;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.CurseforgeMod;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.response.*;
import java.io.*;
import java.net.*;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
public class CurseforgeApi {
// So you found the API key.
// Please be aware that CurseForge requires you to change this if you make any kind of derivative work
// Creating your own API key is relatively simple, so please don't abuse this
private static final String API_KEY = new String(unsalt(new byte[] {
private static final String API_KEY = new String(unsalt(new byte[]{
-30, 50, -60, -121, 62, -31, 35, 17, 16, -53,
-53, -88, 21, -21, 15, -105, -115, -108, 114, -50,
-49, -4, 56, -65, -70, 108, -65, -3, -55, -4,
@ -26,7 +28,7 @@ public class CurseforgeApi {
private static final int pageSize = 20;
public static List<CurseforgeMod> search(String gameVersion, String query, int page, String sort) throws IOException {
return Utils.downloadObject(Utils.buildUrl(API_URL, "mods/search", Map.of(
return Net.downloadObject(Net.buildUrl(API_URL, "mods/search", Map.of(
"gameId", "432", // minecraft
"modLoaderType", "4", // fabric
"classId", "6", // mods
@ -41,7 +43,7 @@ public class CurseforgeApi {
}
public static CurseforgeMod getMod(String slug) throws IOException {
SearchResponse response = Utils.downloadObject(Utils.buildUrl(API_URL, "mods/search", Map.of(
SearchResponse response = Net.downloadObject(Net.buildUrl(API_URL, "mods/search", Map.of(
"gameId", "432",
"classId", "6",
"slug", slug
@ -53,7 +55,7 @@ public class CurseforgeApi {
}
public static CurseforgeMod getMod(int id) throws IOException {
GetModResponse response = Utils.downloadObject(API_URL + "mods/" + id, GetModResponse.class, API_KEY);
GetModResponse response = Net.downloadObject(API_URL + "mods/" + id, GetModResponse.class, API_KEY);
return checkDistribution(response.data);
}
@ -66,7 +68,7 @@ public class CurseforgeApi {
}
public static CurseforgeFile getFile(int modId, int fileId) throws IOException {
GetModFileResponse response = Utils.downloadObject(API_URL + "mods/" + modId + "/files/" + fileId, GetModFileResponse.class, API_KEY);
GetModFileResponse response = Net.downloadObject(API_URL + "mods/" + modId + "/files/" + fileId, GetModFileResponse.class, API_KEY);
return response.data;
}

View File

@ -1,19 +1,14 @@
package io.gitlab.jfronny.inceptum.util.api;
package io.gitlab.jfronny.inceptum.launcher.api;
import io.gitlab.jfronny.gson.reflect.TypeToken;
import io.gitlab.jfronny.inceptum.model.fabric.FabricVersionLoaderInfo;
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.model.mojang.Rules;
import io.gitlab.jfronny.inceptum.model.mojang.VersionInfo;
import io.gitlab.jfronny.inceptum.model.mojang.VersionsListInfo;
import io.gitlab.jfronny.inceptum.util.DeepCloner;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.common.Net;
import io.gitlab.jfronny.inceptum.launcher.model.fabric.FabricVersionLoaderInfo;
import io.gitlab.jfronny.inceptum.launcher.model.inceptum.InstanceMeta;
import io.gitlab.jfronny.inceptum.launcher.model.mojang.*;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.*;
public class FabricMetaApi {
private static final Type fabricLoaderVersionListType = new TypeToken<List<FabricVersionLoaderInfo>>() {}.getType();
@ -21,20 +16,21 @@ public class FabricMetaApi {
public static List<FabricVersionLoaderInfo> getLoaderVersions(VersionsListInfo version) {
try {
return Utils.downloadObject(META_URL + "v2/versions/loader/" + version.id, fabricLoaderVersionListType);
return Net.downloadObject(META_URL + "v2/versions/loader/" + version.id, fabricLoaderVersionListType);
} catch (IOException e) {
throw new RuntimeException("Could not get fabric loader versions", e);
}
}
public static FabricVersionLoaderInfo getLoaderVersion(String gameVersion, String fabricVersion) throws IOException {
return Utils.downloadObject(META_URL + "v2/versions/loader/" + gameVersion + "/" + fabricVersion, FabricVersionLoaderInfo.WithMeta.class);
return Net.downloadObject(META_URL + "v2/versions/loader/" + gameVersion + "/" + fabricVersion, FabricVersionLoaderInfo.WithMeta.class);
}
public static VersionInfo addFabric(VersionInfo version, String fabricVersion, FabricVersionInfoType type) throws IOException {
VersionInfo result = DeepCloner.clone(version);
VersionInfo result = version.clone();
FabricVersionLoaderInfo ver = getLoaderVersion(version.id, fabricVersion);
if (!(ver instanceof FabricVersionLoaderInfo.WithMeta verWithMeta)) throw new IOException("Doesn't hold metadata");
if (!(ver instanceof FabricVersionLoaderInfo.WithMeta verWithMeta))
throw new IOException("Doesn't hold metadata");
FabricVersionLoaderInfo.WithMeta.LauncherMeta meta = verWithMeta.launcherMeta;
if (meta.version != 1) throw new IOException("Unsupported fabric launcherMeta version: " + meta.version);
result.mainClass = type == FabricVersionInfoType.Server ? meta.mainClass.server : meta.mainClass.client;

View File

@ -1,9 +1,10 @@
package io.gitlab.jfronny.inceptum.util.api;
package io.gitlab.jfronny.inceptum.launcher.api;
import io.gitlab.jfronny.commons.OSUtils;
import io.gitlab.jfronny.inceptum.model.mojang.*;
import io.gitlab.jfronny.inceptum.util.MetaHolder;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.commons.io.JFiles;
import io.gitlab.jfronny.inceptum.common.MetaHolder;
import io.gitlab.jfronny.inceptum.common.Net;
import io.gitlab.jfronny.inceptum.launcher.model.mojang.*;
import java.io.IOException;
import java.net.URISyntaxException;
@ -12,7 +13,7 @@ import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import static io.gitlab.jfronny.inceptum.util.Utils.downloadObject;
import static io.gitlab.jfronny.inceptum.common.Net.downloadObject;
public class McApi {
public static VersionsList getVersions() {
@ -32,17 +33,16 @@ public class McApi {
if (!Files.exists(file)) Files.createDirectories(file);
file = file.resolve(info.assetIndex.url.substring(info.assetIndex.url.lastIndexOf("/") + 1));
try {
Utils.downloadFile(info.assetIndex.url, info.assetIndex.sha1, file);
}
catch (IOException | URISyntaxException e) {
Net.downloadFile(info.assetIndex.url, info.assetIndex.sha1, file);
} catch (IOException | URISyntaxException e) {
if (!Files.exists(file)) throw e;
}
return Utils.loadObject(file, AssetIndex.class);
return JFiles.readObject(file, AssetIndex.class);
}
public static Map<String, JvmFileInfo.File> getJvm(String component, int majorVersion) throws IOException {
// https://github.com/ATLauncher/ATLauncher/blob/master/src/main/java/com/atlauncher/constants/Constants.java#L123
JvmInfo info = Utils.downloadObject("https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json", JvmInfo.class);
JvmInfo info = Net.downloadObject("https://launchermeta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json", JvmInfo.class);
Map<String, List<JvmInfo.Jvm>> vms = switch (OSUtils.TYPE) {
case WINDOWS -> info.windowsX64;
case LINUX -> info.linux;
@ -61,6 +61,6 @@ public class McApi {
public static void downloadAsset(AssetIndex.Asset asset, Path path) throws IOException, URISyntaxException {
String url = "http://resources.download.minecraft.net/" + asset.hash.substring(0, 2) + "/" + asset.hash;
Utils.downloadFile(url, asset.hash, path);
Net.downloadFile(url, asset.hash, path);
}
}

View File

@ -1,17 +1,12 @@
package io.gitlab.jfronny.inceptum.util.api;
package io.gitlab.jfronny.inceptum.launcher.api;
import io.gitlab.jfronny.gson.reflect.TypeToken;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthProject;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthProjectType;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthSearchResult;
import io.gitlab.jfronny.inceptum.model.modrinth.ModrinthVersion;
import io.gitlab.jfronny.inceptum.util.Utils;
import io.gitlab.jfronny.inceptum.common.Net;
import io.gitlab.jfronny.inceptum.launcher.model.modrinth.*;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.*;
public class ModrinthApi {
private static final String API_HOST = "https://api.modrinth.com/";
@ -21,7 +16,7 @@ public class ModrinthApi {
//TODO search by categories: facets:[["versions:$ver","versions:$ver"],["categories:$cat","categories:$cat"]]
//TODO filter server/client-only mods
public static ModrinthSearchResult search(String query, int page, String version, ModrinthProjectType type) throws IOException {
return Utils.downloadObject(Utils.buildUrl(API_HOST, "v2/search", Map.of(
return Net.downloadObject(Net.buildUrl(API_HOST, "v2/search", Map.of(
"query", query,
"facets", "[[\"versions:" + version + "\"],[\"categories:fabric\"],[\"project_type:" + type + "\"]]",
"index", "relevance",
@ -31,20 +26,20 @@ public class ModrinthApi {
}
public static ModrinthProject getMod(String id) throws IOException {
return Utils.downloadObject(API_HOST + "v2/project/" + id, ModrinthProject.class);
return Net.downloadObject(API_HOST + "v2/project/" + id, ModrinthProject.class);
}
public static List<ModrinthVersion> getVersions(String mod) throws IOException {
List<ModrinthVersion> versions = Utils.downloadObject(API_HOST + "v2/project/" + mod + "/version", modrinthVersionListType);
List<ModrinthVersion> versions = Net.downloadObject(API_HOST + "v2/project/" + mod + "/version", modrinthVersionListType);
versions.sort(Comparator.comparing(version -> version.date_published));
return versions;
}
public static ModrinthVersion getVersion(String id) throws IOException {
return Utils.downloadObject(API_HOST + "v2/version/" + id, ModrinthVersion.class);
return Net.downloadObject(API_HOST + "v2/version/" + id, ModrinthVersion.class);
}
public static ModrinthVersion getVersionByHash(String sha1) throws IOException {
return Utils.downloadObject(API_HOST + "v2/version_file/" + sha1 + "?algorithm=sha1", ModrinthVersion.class);
return Net.downloadObject(API_HOST + "v2/version_file/" + sha1 + "?algorithm=sha1", ModrinthVersion.class);
}
}

Some files were not shown because too many files have changed in this diff Show More