Refactor to use manifold and records for models
ci/woodpecker/push/docs Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details

This commit is contained in:
Johannes Frohnmeyer 2022-11-18 21:58:40 +01:00
parent 3370495207
commit 18810b255b
Signed by: Johannes
GPG Key ID: E76429612C2929F4
140 changed files with 1430 additions and 1519 deletions

View File

@ -12,8 +12,10 @@ allprojects {
val lwjglVersion by extra("3.3.1")
val imguiVersion by extra("1.86.4")
val jfCommonsVersion by extra("1.0-SNAPSHOT")
val gsonCompileVersion by extra("1.0-SNAPSHOT")
val gsonCompileVersion by extra("1.1-SNAPSHOT")
val manifoldVersion by extra("2022.1.25")
val jlhttpVersion by extra("2.6")
val flavorProp: String by extra(prop("flavor", "custom"))
if (!setOf("custom", "maven", "fat", "windows", "linux", "macos").contains(flavorProp)) throw IllegalStateException("Unsupported flavor: $flavorProp")
val flavor: String by extra(if (flavorProp != "custom") flavorProp else OS.TYPE.codename)

View File

@ -0,0 +1,22 @@
plugins {
id("inceptum.java-conventions")
}
dependencies {
val manifoldVersion: String by rootProject.extra
implementation("systems.manifold:manifold-props-rt:$manifoldVersion")
testAnnotationProcessor(annotationProcessor("systems.manifold:manifold-ext:$manifoldVersion")!!)
testAnnotationProcessor(annotationProcessor("systems.manifold:manifold-props:$manifoldVersion")!!)
}
if (sourceSets.main.get().allJava.files.any {it.name == "module-info.java"}) {
tasks.withType<JavaCompile> {
options.compilerArgs.addAll(arrayOf("-Xplugin:Manifold no-bootstrap", "--module-path", classpath.asPath))
}
} else {
tasks.withType<JavaCompile> {
options.compilerArgs.addAll(arrayOf("-Xplugin:Manifold no-bootstrap"))
}
}

View File

@ -5,6 +5,7 @@ plugins {
id("inceptum.library-conventions")
id("jf.codegen")
id("inceptum.gson-compile")
id("inceptum.manifold")
}
dependencies {
@ -18,6 +19,7 @@ sourceSets {
main {
generate(project) {
`class`("io.gitlab.jfronny.inceptum.common", "BuildMetadata") {
modifiers(Modifier.PUBLIC)
val modifiers = arrayOf(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)
field("VERSION", versionS, *modifiers)

View File

@ -0,0 +1,9 @@
package extensions.java.lang.Iterable;
import manifold.ext.rt.api.Extension;
import manifold.ext.rt.api.Structural;
@Extension
@Structural
public class StructuralIterable {
}

View File

@ -0,0 +1,19 @@
package extensions.java.util.Map;
import manifold.ext.rt.api.Extension;
import manifold.ext.rt.api.This;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
@Extension
public abstract class MapExt<K, V> implements Iterable<Map.Entry<K, V>> {
public static <K, V> Iterator<Map.Entry<K,V>> iterator(@This Map<K, V> thiz) {
return thiz.entrySet().iterator();
}
public static <K, V> V set(@This Map<K, V> thiz, K key, V value) {
return thiz.put(key, value);
}
}

View File

@ -0,0 +1,7 @@
package extensions.java.util.stream.BaseStream;
import manifold.ext.rt.api.Extension;
@Extension
public abstract class BaseStreamExt<T> implements Iterable<T> {
}

View File

@ -0,0 +1,44 @@
package extensions.java.util.stream.Stream;
import manifold.ext.rt.api.Extension;
import manifold.ext.rt.api.This;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Extension
public abstract class StreamExt<T> {
public static <T> Set<T> toSet(@This Stream<T> thiz) {
return thiz.collect(LinkedHashSet::new, Set::add, Set::addAll);
}
public static <T, K, V> Map<K, V> toMap(@This Stream<T> thiz, Function<? super T, K> keyMapper, Function<? super T, V> valueMapper) {
return thiz.collect(Collectors.toMap(keyMapper, valueMapper));
}
public static <T, K> Map<K, T> toMap(@This Stream<T> thiz, Function<? super T, K> keyMapper) {
return thiz.toMap(keyMapper, Function.identity());
}
public static <T, V> Map<V, List<T>> groupingBy(@This Stream<T> thiz, Function<? super T, V> valueMapper) {
return thiz.collect(Collectors.groupingBy(valueMapper));
}
public static String join(@This Stream<String> thiz) {
return thiz.collect(Collectors.joining());
}
public static String join(@This Stream<String> thiz, String delimiter) {
return thiz.collect(Collectors.joining(delimiter));
}
public static String join(@This Stream<String> thiz, char delimiter) {
return thiz.join("" + delimiter);
}
public static <T> Stream<T> concat(@This Stream<T> thiz, Stream<T> other) {
return Stream.concat(thiz, other);
}
}

View File

@ -0,0 +1,14 @@
package extensions.org.w3c.dom.Node;
import manifold.ext.rt.api.Extension;
import manifold.ext.rt.api.This;
import org.w3c.dom.Node;
@Extension
public class NodeExt {
public static boolean isWhitespace(@This Node thiz) {
if (thiz.nodeType == Node.TEXT_NODE && thiz.textContent.isBlank()) return true;
if (thiz.nodeType == Node.COMMENT_NODE) return true;
return false;
}
}

View File

@ -0,0 +1,33 @@
package extensions.org.w3c.dom.NodeList;
import manifold.ext.rt.api.*;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.util.*;
@Extension
public abstract class NodeListExt implements Iterable<Node> {
public static Iterator<Node> iterator(@This NodeList thiz) {
return new Iterator<>() {
private int index = 0;
@Override
public boolean hasNext() {
while (index < thiz.length && thiz[index].isWhitespace()) {
index++;
}
return index < thiz.length;
}
@Override
public Node next() {
if (!hasNext()) throw new NoSuchElementException();
return thiz[index++];
}
};
}
public static Node get(@This NodeList thiz, int index) {
return thiz.item(index);
}
}

View File

@ -0,0 +1,34 @@
package io.gitlab.jfronny.inceptum.common;
import io.gitlab.jfronny.gson.stream.JsonReader;
import io.gitlab.jfronny.gson.stream.JsonWriter;
public class GsonPreset {
public static class Config {
public static void configure(JsonReader reader) {
reader.isSerializeSpecialFloatingPointValues = true;
reader.isLenient = true;
}
public static void configure(JsonWriter writer) {
writer.serializeNulls = true;
writer.isSerializeSpecialFloatingPointValues = true;
writer.isLenient = true;
writer.indent = " ";
writer.omitQuotes = true;
}
}
public static class Api {
public static void configure(JsonReader reader) {
reader.isSerializeSpecialFloatingPointValues = true;
reader.isLenient = true;
}
public static void configure(JsonWriter writer) {
writer.serializeNulls = false;
writer.isSerializeSpecialFloatingPointValues = true;
writer.isLenient = false;
}
}
}

View File

@ -18,8 +18,8 @@ public class InceptumConfig {
public static String authorName = "Inceptum";
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.parent))
Files.createDirectories(MetaHolder.CONFIG_PATH.parent);
if (!Files.exists(MetaHolder.CONFIG_PATH)) {
Path gLaunch2 = MetaHolder.BASE_PATH.resolve("glaunch2.json");
Path json = MetaHolder.BASE_PATH.resolve("inceptum.json");
@ -32,7 +32,7 @@ public class InceptumConfig {
}
}
try (JsonReader jr = new JsonReader(Files.newBufferedReader(MetaHolder.CONFIG_PATH))) {
jr.setLenient(true);
GsonPreset.Config.configure(jr);
jr.beginObject();
while (jr.peek() != JsonToken.END_OBJECT) {
String name = null;
@ -70,9 +70,7 @@ public class InceptumConfig {
public static void saveConfig() {
try (JsonWriter jw = new JsonWriter(Files.newBufferedWriter(MetaHolder.CONFIG_PATH))) {
jw.setLenient(true);
jw.setOmitQuotes(true);
jw.setIndent(" ");
GsonPreset.Config.configure(jw);
jw.beginObject()
.comment("Whether to show snapshots in the version selector for new instances")
.name("snapshots").value(snapshots)

View File

@ -9,11 +9,11 @@ import java.io.IOException;
public class InceptumEnvironmentInitializer {
public static void initialize() throws IOException {
Logger.registerFactory(InceptumEnvironmentInitializer::defaultFactory);
HttpUtils.setUserAgent("jfmods/inceptum/" + BuildMetadata.VERSION);
HttpUtils.userAgent = "jfmods/inceptum/" + BuildMetadata.VERSION;
InceptumConfig.load();
}
public static Logger defaultFactory(String name) {
return new StdoutLogger(name, true, true, true);
return StdoutLogger.fancy(name);
}
}

View File

@ -17,7 +17,7 @@ public class MetaHolder {
case WINDOWS -> getPath(System.getenv("APPDATA"));
case MAC_OS -> getPath(System.getProperty("user.home")).resolve("Library").resolve("Application Support");
case LINUX -> {
String s = System.getenv().get("XDG_CONFIG_HOME");
String s = System.getenv("XDG_CONFIG_HOME");
if (s == null)
yield getPath(System.getProperty("user.home")).resolve(".config");
else

View File

@ -65,11 +65,11 @@ public class Net {
if (url.startsWith("/")) res.append(url);
else res.append("/").append(url);
int i = 0;
for (Map.Entry<String, String> entry : params.entrySet()) {
for (Map.Entry<String, String> entry : params) {
res.append(i++ == 0 ? '?' : '&')
.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
.append(URLEncoder.encode(entry.key, StandardCharsets.UTF_8))
.append('=')
.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
.append(URLEncoder.encode(entry.value, StandardCharsets.UTF_8));
}
return res.toString();
}
@ -83,12 +83,12 @@ public class Net {
}
public static void downloadFile(String url, Path path) throws IOException, URISyntaxException {
if (!Files.exists(path.getParent())) Files.createDirectories(path.getParent());
if (!Files.exists(path.parent)) Files.createDirectories(path.parent);
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());
if (!Files.exists(path.parent)) Files.createDirectories(path.parent);
Files.write(path, downloadData(url, sha1));
}
}

View File

@ -30,10 +30,10 @@ public class ObjectCache {
public <T, TEx extends Throwable> T get(String key, ThrowingSupplier<String, ? extends TEx> download, ThrowingFunction<String, T, ? extends TEx> builder) throws IOException, TEx {
if (!container.containsKey(key)) {
Path cd = cacheDir.resolve(key);
if (Files.exists(cd)) container.put(key, builder.apply(Files.readString(cd)));
else container.put(key, builder.apply(download.get()));
if (Files.exists(cd)) container[key] = builder.apply(Files.readString(cd));
else container[key] = builder.apply(download.get());
}
//noinspection unchecked
return (T) container.get(key);
return (T) container[key];
}
}

View File

@ -1,7 +0,0 @@
package io.gitlab.jfronny.inceptum.common;
public class OutdatedException extends RuntimeException {
public OutdatedException(String message) {
super(message);
}
}

View File

@ -5,11 +5,14 @@ package io.gitlab.jfronny.inceptum.common;
*/
public class R {
public static void nop() {
// No-Op
}
public static void nop(Object a1) {
// No-Op
}
public static void nop(Object a1, Object a2) {
// No-Op
}
}

View File

@ -14,7 +14,6 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Updater {
@ -33,35 +32,36 @@ public class Updater {
public static void update(UpdateMetadata source, boolean relaunch) throws IOException, URISyntaxException {
Utils.LOGGER.info("Downloading version " + source.version);
WrapperConfig config = new WrapperConfig();
config.natives = new HashMap<>();
config.libraries = new LinkedHashSet<>();
config.repositories = new LinkedHashSet<>(source.repositories);
source.natives.forEach((k, v) -> config.natives.put(k, new LinkedHashSet<>(v)));
WrapperConfig config = new WrapperConfig(
new LinkedHashSet<>(),
new LinkedHashSet<>(source.repositories),
new HashMap<>()
);
source.natives.forEach((k, v) -> config.natives[k] = new LinkedHashSet<>(v));
DependencyNode node = downloadLibrary(source.repositories, "io.gitlab.jfronny.inceptum:launcher-dist:" + source.version, config.libraries);
Utils.LOGGER.info("Downloaded Dependencies:\n" + node);
List<String> currentLibraries = new LinkedList<>(config.libraries);
if (source.natives.containsKey(Utils.getCurrentFlavor())) {
if (source.natives.containsKey(Utils.currentFlavor)) {
Set<String> natives = new LinkedHashSet<>();
for (String lib : source.natives.get(Utils.getCurrentFlavor())) {
for (String lib : source.natives[Utils.currentFlavor]) {
downloadLibrary(source.repositories, lib, natives);
}
currentLibraries.addAll(natives);
config.natives.put(Utils.getCurrentFlavor(), natives);
config.natives[Utils.currentFlavor] = natives;
}
GC_WrapperConfig.write(MetaHolder.WRAPPER_CONFIG_PATH, config);
if (relaunch) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
Runtime.runtime.addShutdownHook(new Thread(() -> {
try {
new ProcessBuilder(OSUtils.getJvmBinary(),
new ProcessBuilder(OSUtils.jvmBinary,
"-cp",
buildClasspath(currentLibraries.stream())
.map(Path::toString)
.collect(Collectors.joining("" + File.pathSeparatorChar))
.join(File.pathSeparatorChar)
).inheritIO().start();
} catch (IOException e) {
Utils.LOGGER.error("Could not relaunch", e);
@ -71,7 +71,7 @@ public class Updater {
}
public static List<Path> getLaunchClasspath(WrapperConfig wrapperConfig) throws IOException, URISyntaxException {
Set<String> natives = wrapperConfig.natives.get(Utils.getCurrentFlavor());
Set<String> natives = wrapperConfig.natives[Utils.currentFlavor];
if (natives == null) natives = new LinkedHashSet<>();
Set<String> libs = wrapperConfig.libraries;
if (libs == null) libs = new LinkedHashSet<>();
@ -79,14 +79,14 @@ public class Updater {
boolean configChanged = false;
for (String lib : libs) {
Path p = ArtifactMeta.parse(lib).getLocalPath();
Path p = ArtifactMeta.parse(lib).localPath;
if (!Files.exists(p)) {
configChanged = true;
downloadLibrary(wrapperConfig.repositories, lib, libs);
}
}
for (String lib : natives) {
Path p = ArtifactMeta.parse(lib).getLocalPath();
Path p = ArtifactMeta.parse(lib).localPath;
if (!Files.exists(p)) {
configChanged = true;
downloadLibrary(wrapperConfig.repositories, lib, natives);
@ -95,7 +95,7 @@ public class Updater {
if (configChanged) GC_WrapperConfig.write(MetaHolder.WRAPPER_CONFIG_PATH, wrapperConfig);
return buildClasspath(Stream.concat(libs.stream(), natives.stream())).toList();
return buildClasspath(libs.stream().concat(natives.stream())).toList();
}
private static Stream<Path> buildClasspath(Stream<String> libraries) {
@ -104,7 +104,7 @@ public class Updater {
private static DependencyNode downloadLibrary(Set<String> repositories, final String artifact, Set<String> libraries) throws IOException, URISyntaxException {
List<FileNotFoundException> suppressed = new LinkedList<>();
for (String repository : Stream.concat(Stream.of(PROJECT_MAVEN), repositories.stream()).toList()) {
for (String repository : Stream.of(PROJECT_MAVEN).concat(repositories.stream())) {
ArtifactMeta meta;
try {
meta = MavenApi.getMetadata(repository, artifact);
@ -120,7 +120,7 @@ public class Updater {
suppressed.add(notFound);
continue;
} catch (IOException | URISyntaxException | XMLStreamException | SAXException e) {
throw new IOException("Could not download artifact " + meta.getMavenNotation() + " from " + repository, e);
throw new IOException("Could not download artifact " + meta.mavenNotation + " from " + repository, e);
}
Set<DependencyNode> dependencies = new LinkedHashSet<>();
if (pom.dependencies != null) {
@ -175,7 +175,7 @@ public class Updater {
return switch (channel) {
case CI -> ARTIFACTS_URL;
case Stable -> STABLE_URL;
} + "/Inceptum-" + Utils.getCurrentFlavor() + ".jar";
} + "/Inceptum-" + Utils.currentFlavor + ".jar";
}
public static class UpdateCheckException extends Exception {

View File

@ -17,6 +17,7 @@ import java.util.stream.Collectors;
public class Utils {
public static final int CACHE_SIZE = 128;
public static final Pattern NEW_LINE = Pattern.compile("[\r\n]+");
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();
@ -24,9 +25,9 @@ public class Utils {
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);
Runtime.runtime.exec(new String[]{"xdg-open", uri.toString()});
} else if (Desktop.isDesktopSupported && Desktop.desktop.isSupported(Desktop.Action.BROWSE)) {
Desktop.desktop.browse(uri);
}
} catch (Exception e) {
Utils.LOGGER.error("Error opening web browser!", e);
@ -36,9 +37,9 @@ public class Utils {
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);
Runtime.runtime.exec(new String[]{"xdg-open", file.absoluteFile.toString()});
} else if (Desktop.isDesktopSupported && Desktop.desktop.isSupported(Desktop.Action.BROWSE)) {
Desktop.desktop.open(file);
}
} catch (Exception e) {
Utils.LOGGER.error("Error opening web browser!", e);
@ -67,8 +68,8 @@ public class Utils {
return Arrays.stream(segments)
.map(s -> s.startsWith(separator) ? s.substring(separator.length()) : s)
.map(s -> s.endsWith(separator) ? s.substring(0, s.length() - separator.length()) : s)
.filter(s -> !s.isEmpty())
.collect(Collectors.joining(separator));
.filter(s -> !s.isEmpty)
.join(separator);
}
public static String getCurrentFlavor() {

View File

@ -29,202 +29,147 @@ public class MavenApi {
}
public static Path downloadLibrary(String repo, ArtifactMeta meta) throws IOException, URISyntaxException {
Path res = meta.getLocalPath();
Path res = meta.localPath;
Net.downloadFile(Utils.join("/", repo, meta.getJarPath(true)), res);
return res;
}
public static Pom getPom(String repo, ArtifactMeta meta) throws IOException, SAXException, URISyntaxException, XMLStreamException {
try (InputStream is = HttpUtils.get(Utils.join("/", repo, meta.getPomPath())).sendInputStream()) {
try (InputStream is = HttpUtils.get(Utils.join("/", repo, meta.pomPath)).sendInputStream()) {
Document doc = FACTORY.parse(is);
doc.getDocumentElement().normalize();
Pom result = new Pom();
if (!"project".equals(doc.getDocumentElement().getNodeName())) throw new IOException("Illegal document name");
boolean hasModelVersion = false;
boolean hasGroupId = false;
boolean hasArtifactId = false;
boolean hasVersion = false;
for (Node node : iterable(doc.getDocumentElement().getChildNodes())) {
switch (node.getNodeName()) {
case "modelVersion" -> {
hasModelVersion = true;
result.modelVersion = node.getTextContent();
}
doc.documentElement.normalize();
if (!"project".equals(doc.documentElement.nodeName)) throw new IOException("Illegal document name");
String modelVersion = null;
String groupId = null;
String artifactId = null;
String version = null;
String packaging = null;
List<MavenDependency> dependencies = null;
String classifier = null;
for (Node node : doc.documentElement.childNodes) {
switch (node.nodeName) {
case "modelVersion" -> modelVersion = node.textContent;
case "parent" -> {
// Dirty hack to get slf4j working: simply assume the groupId and version of the parent is also the groupId of this
if (!hasGroupId) {
for (Node child : iterable(node.getChildNodes())) {
switch (child.getNodeName()) {
if (groupId == null) {
for (Node child : node.childNodes) {
switch (child.nodeName) {
case "groupId" -> {
if (!hasGroupId) {
hasGroupId = true;
result.groupId = node.getTextContent();
if (groupId == null) {
groupId = node.textContent;
}
}
case "version" -> {
if (!hasVersion) {
hasVersion = true;
result.version = node.getTextContent();
if (version == null) {
version = node.textContent;
}
}
}
}
}
}
case "groupId" -> {
hasGroupId = true;
result.groupId = node.getTextContent();
}
case "groupId" -> groupId = node.textContent;
case "artifactId" -> {
hasArtifactId = true;
result.artifactId = node.getTextContent();
artifactId = node.textContent;
}
case "version" -> {
hasVersion = true;
result.version = node.getTextContent();
version = node.textContent;
}
case "packaging" -> result.packaging = node.getTextContent();
case "packaging" -> packaging = node.textContent;
case "dependencies" -> {
result.dependencies = new LinkedList<>();
for (Node dep : iterable(node.getChildNodes())) {
dependencies = new LinkedList<>();
for (Node dep : node.childNodes) {
MavenDependency resolved = parseDependency(dep);
if (resolved != null) {
result.dependencies.add(resolved);
dependencies.add(resolved);
}
}
}
case "classifier" -> result.classifier = node.getTextContent();
case "classifier" -> classifier = node.textContent;
default -> {}
}
}
if (!hasModelVersion) throw new IOException("Pom lacks modelVersion");
if (!hasGroupId) throw new IOException("Pom lacks groupId");
if (!hasArtifactId) throw new IOException("Pom lacks artifactId");
if (!hasVersion) throw new IOException("Pom lacks version");
return result;
if (modelVersion == null) throw new IOException("Pom lacks modelVersion");
if (groupId == null) throw new IOException("Pom lacks groupId");
if (artifactId == null) throw new IOException("Pom lacks artifactId");
if (version == null) throw new IOException("Pom lacks version");
return new Pom(modelVersion, groupId, artifactId, version, classifier, null, packaging, dependencies);
}
}
private static @Nullable MavenDependency parseDependency(Node doc) throws IOException {
MavenDependency result = new MavenDependency();
boolean hasGroupId = false;
boolean hasArtifactId = false;
boolean hasVersion = false;
boolean hasScope = false;
for (Node node : iterable(doc.getChildNodes())) {
switch (node.getNodeName()) {
case "groupId" -> {
hasGroupId = true;
result.groupId = node.getTextContent();
}
case "artifactId" -> {
hasArtifactId = true;
result.artifactId = node.getTextContent();
}
case "version" -> {
hasVersion = true;
result.version = node.getTextContent();
}
String groupId = null;
String artifactId = null;
String version = null;
String scope = null;
for (Node node : doc.childNodes) {
switch (node.nodeName) {
case "groupId" -> groupId = node.textContent;
case "artifactId" -> artifactId = node.textContent;
case "version" -> version = node.textContent;
case "scope" -> {
hasScope = true;
result.scope = node.getTextContent();
if (!RUNTIME_SCOPES.contains(result.scope)) return null;
scope = node.textContent;
if (!RUNTIME_SCOPES.contains(scope)) return null;
}
case "optional" -> {
if (node.getTextContent().equals("true")) return null;
if (node.textContent.equals("true")) return null;
}
}
}
if (!hasGroupId) throw new IOException("Pom lacks groupId");
if (!hasArtifactId) throw new IOException("Pom lacks artifactId");
if (!hasVersion) {
if (result.groupId.equals("org.lwjgl")) {
if (groupId == null) throw new IOException("Pom lacks groupId");
if (artifactId == null) throw new IOException("Pom lacks artifactId");
if (version == null) {
if (groupId.equals("org.lwjgl")) {
// Lwjgl uses a shared bom for versions which I don't want to support
// The required modules are explicit dependencies of launcher-imgui anyway
return null;
}
throw new IOException("Dependency " + result.groupId + ":" + result.artifactId + " lacks version");
throw new IOException("Dependency " + groupId + ":" + artifactId + " lacks version");
}
if (!hasScope) throw new IOException("Pom lacks scope");
return result;
if (scope == null) throw new IOException("Pom lacks scope");
return new MavenDependency(groupId, artifactId, version, scope);
}
public static ArtifactMeta getMetadata(String repo, String artifact) throws IOException, SAXException, URISyntaxException {
ArtifactMeta sourceMeta = ArtifactMeta.parse(artifact);
try (InputStream is = HttpUtils.get(Utils.join("/", repo, sourceMeta.getMetadataPath())).sendInputStream()) {
try (InputStream is = HttpUtils.get(Utils.join("/", repo, sourceMeta.metadataPath)).sendInputStream()) {
Document doc = FACTORY.parse(is);
doc.getDocumentElement().normalize();
ArtifactMeta result = new ArtifactMeta();
if (!"metadata".equals(doc.getDocumentElement().getNodeName())) throw new IOException("Illegal document name");
boolean hasGroupId = false;
boolean hasArtifactId = false;
boolean hasVersion = false;
for (Node node : iterable(doc.getDocumentElement().getChildNodes())) {
switch (node.getNodeName()) {
case "groupId" -> {
hasGroupId = true;
result.groupId = node.getTextContent();
}
case "artifactId" -> {
hasArtifactId = true;
result.artifactId = node.getTextContent();
}
case "version" -> {
hasVersion = true;
result.version = node.getTextContent();
}
doc.documentElement.normalize();
if (!"metadata".equals(doc.documentElement.nodeName)) throw new IOException("Illegal document name");
String groupId = null;
String artifactId = null;
String version = null;
String snapshotVersion = null;
for (Node node : doc.documentElement.childNodes) {
switch (node.nodeName) {
case "groupId" -> groupId = node.textContent;
case "artifactId" -> artifactId = node.textContent;
case "version" -> version = node.textContent;
case "versioning" -> {
for (Node node1 : iterable(node.getChildNodes())) {
if (node1.getNodeName().equals("snapshot")) {
for (Node node1 : node.childNodes) {
if (node1.nodeName.equals("snapshot")) {
String timestamp = null;
String buildNumber = null;
for (Node node2 : iterable(node1.getChildNodes())) {
switch (node2.getNodeName()) {
case "timestamp" -> timestamp = node2.getTextContent();
case "buildNumber" -> buildNumber = node2.getTextContent();
for (Node node2 : node1.childNodes) {
switch (node2.nodeName) {
case "timestamp" -> timestamp = node2.textContent;
case "buildNumber" -> buildNumber = node2.textContent;
default -> {}
}
}
if (timestamp == null) throw new IOException("Pom snapshots lack timestamp");
if (buildNumber == null) throw new IOException("Pom snapshots lack buildNumber");
result.snapshotVersion = timestamp + '-' + buildNumber;
snapshotVersion = timestamp + '-' + buildNumber;
}
}
}
default -> {}
}
}
if (!hasGroupId) throw new IOException("Pom lacks groupId");
if (!hasArtifactId) throw new IOException("Pom lacks artifactId");
if (!hasVersion) throw new IOException("Pom lacks version");
result.classifier = sourceMeta.classifier;
return result;
if (groupId == null) throw new IOException("Pom lacks groupId");
if (artifactId == null) throw new IOException("Pom lacks artifactId");
if (version == null) throw new IOException("Pom lacks version");
return new ArtifactMeta(groupId, artifactId, version, sourceMeta.classifier, snapshotVersion);
}
}
private static Iterable<Node> iterable(NodeList list) {
return () -> new Iterator<>() {
int index = 0;
@Override
public boolean hasNext() {
while (index < list.getLength() && isWhitespace(list.item(index))) {
index++;
}
return index < list.getLength();
}
@Override
public Node next() {
if (!hasNext()) throw new NoSuchElementException();
return list.item(index++);
}
};
}
private static boolean isWhitespace(Node node) {
if (node.getNodeType() == Node.TEXT_NODE && node.getTextContent().isBlank()) return true;
if (node.getNodeType() == Node.COMMENT_NODE) return true;
return false;
}
}

View File

@ -1,18 +1,18 @@
package io.gitlab.jfronny.inceptum.common.model.inceptum;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Map;
import java.util.Set;
@GSerializable
public class UpdateMetadata {
public Integer wrapperVersion;
public String version;
public Long buildTime;
public Boolean isPublic;
public Boolean isRelease;
public Integer jvm;
public Set<String> repositories;
public Map<String, Set<String>> natives;
@GSerializable(configure = GsonPreset.Api.class)
public record UpdateMetadata(int wrapperVersion,
String version,
long buildTime,
boolean isPublic,
boolean isRelease,
int jvm,
Set<String> repositories,
Map<String, Set<String>> natives) {
}

View File

@ -1,13 +1,11 @@
package io.gitlab.jfronny.inceptum.common.model.inceptum;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Map;
import java.util.Set;
@GSerializable
public class WrapperConfig {
public Set<String> libraries;
public Set<String> repositories;
public Map<String, Set<String>> natives;
@GSerializable(configure = GsonPreset.Config.class)
public record WrapperConfig(Set<String> libraries, Set<String> repositories, Map<String, Set<String>> natives) {
}

View File

@ -1,32 +1,25 @@
package io.gitlab.jfronny.inceptum.common.model.maven;
import io.gitlab.jfronny.inceptum.common.MetaHolder;
import org.jetbrains.annotations.Nullable;
import java.nio.file.Path;
import java.util.Objects;
public class ArtifactMeta {
public record ArtifactMeta(String groupId, String artifactId, String version, @Nullable String classifier, @Nullable String snapshotVersion) {
public ArtifactMeta(String groupId, String artifactId, String version) {
this(groupId, artifactId, version, null, null);
}
public static ArtifactMeta parse(String mavenNotation) {
if (Objects.requireNonNull(mavenNotation).isEmpty()) throw new IllegalArgumentException("The notation is empty");
String[] lib = mavenNotation.split(":");
if (lib.length <= 1) throw new IllegalArgumentException("Not in maven notation");
if (lib.length == 2) throw new IllegalArgumentException("Skipping versions is not supported");
if (lib.length >= 5) throw new IllegalArgumentException("Unkown elements in maven notation");
ArtifactMeta meta = new ArtifactMeta();
meta.groupId = lib[0];
meta.artifactId = lib[1];
meta.version = lib[2];
if (lib.length > 3) meta.classifier = lib[3];
return meta;
return new ArtifactMeta(lib[0], lib[1], lib[2], lib.length > 3 ? lib[3] : null, null);
}
public String groupId;
public String artifactId;
public String version;
public String classifier;
public String snapshotVersion;
public String getPomPath() {
String path = groupId.replace('.', '/') + '/';
path += artifactId + '/';

View File

@ -2,28 +2,7 @@ package io.gitlab.jfronny.inceptum.common.model.maven;
import java.util.*;
public class DependencyNode {
private final String name;
private final Set<DependencyNode> dependencies;
public DependencyNode(String name, Set<DependencyNode> dependencies) {
this.name = Objects.requireNonNull(name);
this.dependencies = Objects.requireNonNull(dependencies);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DependencyNode that = (DependencyNode) o;
return name.equals(that.name) && dependencies.equals(that.dependencies);
}
@Override
public int hashCode() {
return Objects.hash(name, dependencies);
}
public record DependencyNode(String name, Set<DependencyNode> dependencies) {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();

View File

@ -1,8 +1,4 @@
package io.gitlab.jfronny.inceptum.common.model.maven;
public class MavenDependency {
public String groupId;
public String artifactId;
public String version;
public String scope;
public record MavenDependency(String groupId, String artifactId, String version, String scope) {
}

View File

@ -4,13 +4,12 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
public class Pom {
public String modelVersion;
public String groupId;
public String artifactId;
public String version;
public String classifier;
public String snapshotVersion;
@Nullable public String packaging;
@Nullable public List<MavenDependency> dependencies;
public record Pom(String modelVersion,
String groupId,
String artifactId,
String version,
String classifier,
String snapshotVersion,
@Nullable String packaging,
@Nullable List<MavenDependency> dependencies) {
}

View File

@ -1,5 +1,6 @@
plugins {
id("inceptum.application-conventions")
id("inceptum.manifold")
}
application {

View File

@ -11,11 +11,7 @@ import java.nio.file.Path;
import java.util.List;
public abstract class BaseInstanceCommand extends Command {
public BaseInstanceCommand(String help, String usage, String... aliases) {
super(help, mutateUsage(usage), aliases);
}
public BaseInstanceCommand(String help, String usage, List<String> aliases, List<Command> subCommands) {
protected BaseInstanceCommand(String help, String usage, List<String> aliases, List<Command> subCommands) {
super(help, mutateUsage(usage), aliases, subCommands);
}
@ -36,9 +32,9 @@ public abstract class BaseInstanceCommand extends Command {
Utils.LOGGER.error("You must specify an instance to commit in");
return;
}
Path instancePath = MetaHolder.INSTANCE_DIR.resolve(args.get(0));
Path instancePath = MetaHolder.INSTANCE_DIR.resolve(args[0]);
if (!Files.exists(instancePath)) {
Utils.LOGGER.error("Invalid instance: \"" + args.get(0) + "\"");
Utils.LOGGER.error("Invalid instance: \"" + args[0] + "\"");
return;
}
Instance instance;

View File

@ -22,7 +22,7 @@ public class CliMain {
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));
throw new RuntimeException("Could not find command: " + args[0]);
}
@Override

View File

@ -24,7 +24,7 @@ public abstract class Command {
}
public String getName() {
return aliases.get(0);
return aliases[0];
}
public boolean enableLog() {
@ -36,22 +36,22 @@ public abstract class Command {
public CommandResolution resolve(CommandArgs args) {
if (args.length != 0) {
for (Command command : subCommands) {
if (command.isAlias(args.get(0))) {
if (command.isAlias(args[0])) {
CommandResolution resolution = command.resolve(args.subArgs());
if (!aliases.isEmpty()) resolution.resolvePath().add(0, aliases.get(0));
if (!aliases.isEmpty) resolution.resolvePath.add(0, aliases[0]);
return resolution;
}
}
}
return new CommandResolution(this, args, aliases.isEmpty()
return new CommandResolution(this, args, aliases.isEmpty
? new ArrayList<>()
: new ArrayList<>(List.of(aliases.get(0))));
: new ArrayList<>(List.of(aliases[0])));
}
public void buildHelp(HelpBuilder builder) {
builder.writeCommand(aliases, help, usage);
for (Command command : subCommands) {
command.buildHelp(aliases.isEmpty() ? builder : builder.beginSubcommand(aliases.get(0)));
command.buildHelp(aliases.isEmpty ? builder : builder.beginSubcommand(aliases[0]));
}
}
}

View File

@ -16,11 +16,11 @@ public class CommandArgs implements Iterable<String> {
}
public String last() {
return args.get(args.size() - 1);
return args[args.size() - 1];
}
public String get(int index) {
return args.get(index);
return args[index];
}
public List<String> after(String param) {

View File

@ -31,22 +31,22 @@ public class HelpBuilder {
}
public void writeCommand(List<String> aliases, String help, String usage) {
if (aliases.isEmpty()) return;
if (aliases.isEmpty) return;
String indent = " ".repeat(level * 2);
builder.append('\n').append(indent).append("- ");
for (int i = 0, aliasesSize = aliases.size(); i < aliasesSize; i++) {
String alias = aliases.get(i);
String alias = aliases[i];
builder.append(alias);
if (i < aliasesSize - 1)
builder.append(", ");
}
builder.append(": ").append(help.replace("\n", "\n " + indent));
if (level == 0 && !usage.isBlank() && !aliases.isEmpty()) {
if (level == 0 && !usage.isBlank()) {
StringBuilder usagePrefix = new StringBuilder("inceptum");
for (String s : upper) {
usagePrefix.append(" ").append(s);
}
usagePrefix.append(" ").append(aliases.get(0)).append(" ");
usagePrefix.append(" ").append(aliases[0]).append(" ");
builder.append("\n ")
.append(indent)
.append("Usage: ")

View File

@ -26,7 +26,7 @@ public class ExportCommand extends BaseInstanceCommand {
if (args.length == 0) throw new IllegalAccessException("You must specify a target path");
if (args.length == 1) throw new IllegalAccessException("You must specify a version number");
if (args.length != 2) throw new IllegalAccessException("Too many arguments");
Exporters.CURSE_FORGE.generate(new ProcessState(), instance, Paths.get(args.get(0)), args.get(1));
Exporters.CURSE_FORGE.generate(new ProcessState(), instance, Paths.get(args[0]), args[1]);
}
private static class MultiMCExportCommand extends BaseInstanceCommand {
@ -38,7 +38,7 @@ public class ExportCommand extends BaseInstanceCommand {
protected void invoke(CommandArgs args, Instance instance) throws Exception {
if (args.length == 0) throw new IllegalAccessException("You must specify a target path");
if (args.length != 1) throw new IllegalAccessException("Too many arguments");
Exporters.MULTI_MC.generate(new ProcessState(), instance, Paths.get(args.get(0)), "1.0");
Exporters.MULTI_MC.generate(new ProcessState(), instance, Paths.get(args[0]), "1.0");
}
}
@ -52,7 +52,7 @@ public class ExportCommand extends BaseInstanceCommand {
if (args.length == 0) throw new IllegalAccessException("You must specify a target path");
if (args.length == 1) throw new IllegalAccessException("You must specify a version number");
if (args.length != 2) throw new IllegalAccessException("Too many arguments");
Exporters.MODRINTH.generate(new ProcessState(), instance, Paths.get(args.get(0)), args.get(1));
Exporters.MODRINTH.generate(new ProcessState(), instance, Paths.get(args[0]), args[1]);
}
}
}

View File

@ -19,16 +19,16 @@ public class HelpCommand extends Command {
CliMain.COMMANDS_ROOT.buildHelp(help);
} else {
CommandResolution resolution = CliMain.COMMANDS_ROOT.resolve(args);
if (resolution.resolvePath().isEmpty()) {
if (resolution.resolvePath.isEmpty) {
System.err.println("Could not find command matching your input");
invoke(new CommandArgs(List.of()));
return;
}
printHeader();
System.out.println("\nFound matching: \"" + String.join(" ", resolution.resolvePath()) + "\"");
resolution.command().buildHelp(help);
System.out.println("\nFound matching: \"" + String.join(" ", resolution.resolvePath) + "\"");
resolution.command.buildHelp(help);
}
System.out.println(help.getResult());
System.out.println(help.result);
}
private static void printHeader() {

View File

@ -19,7 +19,7 @@ public class ImportCommand extends Command {
if (args.length == 0) throw new IllegalAccessException("You must specify a pack file");
if (args.length != 1) throw new IllegalAccessException("Too many arguments");
ProcessState state = new ProcessState();
String name = Importers.importPack(Paths.get(args.get(0)), state).getFileName().toString();
String name = Importers.importPack(Paths.get(args[0]), state).fileName.toString();
System.out.println(OutputColors.GREEN_BOLD + "Imported as " + name + OutputColors.RESET);
}
}

View File

@ -21,11 +21,10 @@ public class JvmStateCommand extends Command {
System.out.println("Classloader " + loader + ":");
if (loader instanceof URLClassLoader uc)
System.out.println("\t" + Arrays.toString(uc.getURLs()));
System.out.println("\t" + Arrays.toString(uc.uRLs));
else
System.out.println("\t(cannot display components as not a URLClassLoader)");
if (loader.getParent() != null)
dumpClasspath(loader.getParent());
if (loader.getParent() != null) dumpClasspath(loader.getParent());
}
}

View File

@ -46,11 +46,13 @@ public class LaunchCommand extends BaseInstanceCommand {
return;
}
if (args.length > 1) {
InstanceMeta meta = instance.meta();
if (meta.arguments == null) meta.arguments = new InstanceMeta.Arguments();
meta.arguments.client = meta.arguments.client == null ? new ArrayList<>() : new ArrayList<>(meta.arguments.client);
meta.arguments.server = meta.arguments.server == null ? new ArrayList<>() : new ArrayList<>(meta.arguments.server);
meta.arguments.jvm = meta.arguments.jvm == null ? new ArrayList<>() : new ArrayList<>(meta.arguments.jvm);
InstanceMeta meta = instance.meta;
if (meta.arguments == null) meta.arguments = new InstanceMeta.Arguments(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
else meta.arguments = new InstanceMeta.Arguments(
meta.arguments.jvm == null ? new ArrayList<>() : new ArrayList<>(meta.arguments.jvm),
meta.arguments.client == null ? new ArrayList<>() : new ArrayList<>(meta.arguments.client),
meta.arguments.server == null ? new ArrayList<>() : new ArrayList<>(meta.arguments.server)
);
meta.arguments.client.addAll(args.after(0));
meta.arguments.server.addAll(args.after(0));
}

View File

@ -21,13 +21,13 @@ public class ListCommand extends Command {
@Override
protected void invoke(CommandArgs args) throws IOException {
List<Path> paths = JFiles.list(MetaHolder.INSTANCE_DIR);
if (paths.isEmpty()) System.out.println("No instances are currently present");
if (paths.isEmpty) System.out.println("No instances are currently present");
for (Path path : paths) {
if (!Files.exists(path.resolve("instance.json"))) {
System.out.println("- Invalid instance: " + path + " (no instance metadata)");
continue;
}
System.out.println("- \"" + path.getFileName().toString() + "\"");
System.out.println("- \"" + path.fileName.toString() + "\"");
Instance instance;
try {
instance = InstanceList.read(path);
@ -39,13 +39,13 @@ public class ListCommand extends Command {
System.out.println(" Status: Setting up");
continue;
}
System.out.println(" Status: " + (instance.isRunningLocked() ? "Running" : "Stopped"));
System.out.println(" Version: " + instance.getGameVersion());
if (instance.isFabric()) System.out.println(" Fabric Loader: " + instance.getLoaderVersion());
if (instance.meta().java != null) System.out.println(" Custom Java: " + instance.meta().java);
if (instance.meta().minMem != null || instance.meta().maxMem != null)
System.out.println(" Memory:" + (instance.meta().minMem != null ? " Minimum: " + instance.meta().minMem : "")
+ (instance.meta().maxMem != null ? " Maximum: " + instance.meta().maxMem : ""));
System.out.println(" Status: " + (instance.isRunningLocked ? "Running" : "Stopped"));
System.out.println(" Version: " + instance.gameVersion);
if (instance.isFabric) System.out.println(" Fabric Loader: " + instance.loaderVersion);
if (instance.meta.java != null) System.out.println(" Custom Java: " + instance.meta.java);
if (instance.meta.minMem != null || instance.meta().maxMem != null)
System.out.println(" Memory:" + (instance.meta.minMem != null ? " Minimum: " + instance.meta.minMem : "")
+ (instance.meta.maxMem != null ? " Maximum: " + instance.meta.maxMem : ""));
}
}
}

View File

@ -7,7 +7,6 @@ import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.system.instance.Instance;
import io.gitlab.jfronny.inceptum.launcher.system.instance.Mod;
import io.gitlab.jfronny.inceptum.launcher.system.mds.ModsDirScanner;
import io.gitlab.jfronny.inceptum.launcher.system.source.ModSource;
import io.gitlab.jfronny.inceptum.launcher.util.Unchecked;
import java.io.FileNotFoundException;
@ -47,27 +46,26 @@ public class ModCommand extends Command {
@Override
protected void invoke(CommandArgs args, Instance instance) throws IOException {
if (!instance.isFabric()) {
if (!instance.isFabric) {
System.err.println("This is not a fabric instance");
return;
}
System.out.println("Scanning installed mods, this might take a while");
instance.mds().runOnce((path, mod) -> {
boolean hasSources = !mod.getMetadata().sources.isEmpty();
boolean updatable = hasSources && mod.getMetadata().sources.values().stream().anyMatch(Optional::isPresent);
instance.mds.runOnce((path, mod) -> {
boolean hasSources = !mod.metadata.sources.isEmpty;
boolean updatable = hasSources && mod.metadata.sources.values().stream().anyMatch(Optional::isPresent);
if (filterUpdatable && !updatable) return;
System.out.println("- " + path.getFileName().toString());
System.out.println(" " + mod.getName());
for (String s : mod.getDescription()) {
System.out.println("- " + path.fileName.toString());
System.out.println(" " + mod.name);
for (String s : mod.description) {
System.out.println(" " + s);
}
if (hasSources) {
System.out.println(" Sources:");
for (Map.Entry<ModSource, Optional<ModSource>> entry : mod.getMetadata().sources.entrySet()) {
System.out.println(" - " + entry.getKey().getName() + " (" + entry.getKey().getVersion() + ")");
System.out.println(" Local: " + entry.getKey().getJarPath().toString());
if (entry.getValue().isPresent())
System.out.println(" Updatable to: " + entry.getValue().get().getVersion());
for (var entry : mod.metadata.sources) {
System.out.println(" - " + entry.key.name + " (" + entry.key.version + ")");
System.out.println(" Local: " + entry.key.jarPath.toString());
if (entry.value.isPresent) System.out.println(" Updatable to: " + entry.value.get().version);
}
}
});
@ -100,22 +98,22 @@ public class ModCommand extends Command {
}
Set<Path> mods = new HashSet<>();
for (String arg : args) {
Path p = instance.modsDir().resolve(arg);
if (!Files.exists(p)) p = instance.modsDir().resolve(arg + ".imod");
Path p = instance.modsDir.resolve(arg);
if (!Files.exists(p)) p = instance.modsDir.resolve(arg + ".imod");
if (!Files.exists(p)) {
Utils.LOGGER.error("Nonexistant mod file: " + instance.modsDir().resolve(arg));
Utils.LOGGER.error("Nonexistant mod file: " + instance.modsDir.resolve(arg));
return;
}
mods.add(p);
}
ModsDirScanner mds = instance.mds();
if (!ignoreDependencies && !mds.isComplete()) {
ModsDirScanner mds = instance.mds;
if (!ignoreDependencies && !mds.isComplete) {
Utils.LOGGER.error("Scanning mods dir to search for dependencies. This might take a while");
mds.runOnce((path, mod) -> System.out.println("Scanned " + path));
}
for (Path mod : mods) {
try {
mds.get(mod).delete();
mds[mod].delete();
} catch (IOException e) {
Utils.LOGGER.error("Could not delete " + mod, e);
return;
@ -157,23 +155,23 @@ public class ModCommand extends Command {
if (args.length == 0) {
throw new IllegalArgumentException("You must specify mods to remove");
}
Set<Path> mods = pathSupplier.apply(args, instance.path());
ModsDirScanner mds = instance.mds();
if (!mds.isComplete()) {
Set<Path> mods = pathSupplier.apply(args, instance.path);
ModsDirScanner mds = instance.mds;
if (!mds.isComplete) {
Utils.LOGGER.error("Scanning mods dir to search for dependencies. This might take a while");
mds.runOnce((path, mod) -> System.out.println("Scanned " + path));
}
for (Path mod : mods) {
try {
mds.get(mod).delete();
Mod md = mds.get(mod);
md.getMetadata().sources.values().stream()
Mod md = mds[mod];
md.delete();
md.metadata.sources.values().stream()
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.ifPresentOrElse(update -> {
try {
Utils.LOGGER.info("Updating " + mod + " to " + update.getVersion());
Utils.LOGGER.info("Updating " + mod + " to " + update.version);
md.update(update);
Utils.LOGGER.info("Update completed");
} catch (IOException e) {

View File

@ -10,7 +10,7 @@ public class AboutWindow extends AboutDialog {
public AboutWindow() {
setProgramName(new Str("Inceptum"));
setCopyright(new Str("Copyright (C) 2021 JFronny"));
setVersion(new Str(BuildMetadata.VERSION.toString()));
setVersion(new Str(BuildMetadata.VERSION));
setLicenseType(License.MIT_X11);
setLicense(I18n.str("about.license"));
setWebsiteLabel(I18n.str("about.contact"));

View File

@ -1,5 +1,6 @@
plugins {
id("inceptum.application-conventions")
id("inceptum.manifold")
}
application {

View File

@ -65,7 +65,7 @@ public class GuiMain {
AccountManager.loadAccounts();
Utils.LOGGER.info("Initializing UI");
try {
InstanceList.forEach(instance -> instance.mds().start());
InstanceList.forEach(instance -> instance.mds.start());
} catch (IOException e) {
Utils.LOGGER.error("Could not initialize MDS", e);
}
@ -149,7 +149,7 @@ public class GuiMain {
GLFW.glfwGetWindowSize(handle, pWidth, pHeight);
final GLFWVidMode vidmode = Objects.requireNonNull(GLFW.glfwGetVideoMode(GLFW.glfwGetPrimaryMonitor()));
GLFW.glfwSetWindowPos(handle, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight.get(0)) / 2);
GLFW.glfwSetWindowPos(handle, (vidmode.width() - pWidth.get(0)) / 2, (vidmode.height() - pHeight[0]) / 2);
}
GLFW.glfwMakeContextCurrent(handle);
@ -186,7 +186,7 @@ public class GuiMain {
io.addConfigFlags(ImGuiConfigFlags.ViewportsEnable);
io.setConfigViewportsNoAutoMerge(true);
try (InputStream is = LauncherEnv.class.getClassLoader().getResourceAsStream("font.ttf")) {
io.setFontDefault(io.getFonts().addFontFromMemoryTTF(Objects.requireNonNull(is).readAllBytes(), 16f));
io.fontDefault = io.fonts.addFontFromMemoryTTF(Objects.requireNonNull(is).readAllBytes(), 16f);
} catch (IOException e) {
Utils.LOGGER.error("Could not load font", e);
}
@ -206,24 +206,24 @@ public class GuiMain {
if (WINDOWS.isEmpty()) exit();
else {
for (Window window : WINDOWS.toArray(new Window[0])) {
if (window.isNew()) window.preFirstDraw();
String title = window.getName() + "##" + System.identityHashCode(window);
if (window.isCloseable()) {
if (ImGui.begin(title, window.getOpenState(), window.getFlags())) {
if (window.isNew) window.preFirstDraw();
String title = window.name + "##" + System.identityHashCode(window);
if (window.isCloseable) {
if (ImGui.begin(title, window.openState, window.flags)) {
window.draw();
}
} else {
if (ImGui.begin(title, window.getFlags())) {
if (ImGui.begin(title, window.flags)) {
window.draw();
}
}
ImGui.end();
if (!window.getOpenState().get() && !window.isClosed()) window.close();
if (!window.openState.get() && !window.isClosed) window.close();
}
}
//end frame
ImGui.render();
imGuiGl3.renderDrawData(ImGui.getDrawData());
imGuiGl3.renderDrawData(ImGui.drawData);
if (ImGui.getIO().hasConfigFlags(ImGuiConfigFlags.ViewportsEnable)) {
final long backupWindowPtr = GLFW.glfwGetCurrentContext();

View File

@ -34,21 +34,21 @@ public class InstanceManageControls {
private FabricVersionLoaderInfo selectedFabric;
public InstanceManageControls(@Nullable Instance instance) {
selected = getVersions(false).get(0);
selected = getVersions(false)[0];
if (instance != null) {
for (VersionsListInfo ver : getVersions(true)) {
if (ver.id.equals(instance.getGameVersion()))
if (ver.id.equals(instance.gameVersion))
selected = ver;
}
}
version.set(getVersions(snapshots.get()).indexOf(selected));
name.set(instance == null ? InstanceNameTool.getDefaultName(selected.id, fabric.get()) : instance.getName());
fabric.set(instance == null || instance.isFabric());
List<FabricVersionLoaderInfo> versions = getFabricLoaderInfo();
name.set(instance == null ? InstanceNameTool.getDefaultName(selected.id, fabric.get()) : instance.name);
fabric.set(instance == null || instance.isFabric);
List<FabricVersionLoaderInfo> versions = fabricLoaderInfo;
for (int i = 0, fabricLoaderInfoSize = versions.size(); i < fabricLoaderInfoSize; i++) {
FabricVersionLoaderInfo version = versions.get(i);
if (instance != null && instance.isFabric()
? version.loader.version.equals(instance.getLoaderVersion())
FabricVersionLoaderInfo version = versions[i];
if (instance != null && instance.isFabric
? version.loader.version.equals(instance.loaderVersion)
: version.loader.stable) {
selectedFabric = version;
fabricVersion.set(i);
@ -74,7 +74,7 @@ public class InstanceManageControls {
InceptumConfig.snapshots = snapshots.get();
InceptumConfig.saveConfig();
//fix version index
int i = getVersions(InceptumConfig.snapshots).indexOf(getVersions(prev).get(version.get()));
int i = getVersions(InceptumConfig.snapshots).indexOf(getVersions(prev)[version.get()]);
if (i == -1) version.set(0);
else version.set(i);
}
@ -84,16 +84,16 @@ public class InstanceManageControls {
List<VersionsListInfo> vil = getVersions(InceptumConfig.snapshots);
String originalStr = null;
try {
originalStr = getVersionInfo().id;
originalStr = versionInfo.id;
} catch (Throwable e) {
Utils.LOGGER.error("Could not get version string", e);
}
if (ImGui.combo("Version", version, vil.stream().map(info -> info.id).toArray(String[]::new))) {
VersionsListInfo prev = selected;
selected = vil.get(version.get());
selected = vil[version.get()];
exchangeNameIfDefault(prev.id, fabric.get());
}
if (getFabricLoaderInfo().isEmpty()) {
if (fabricLoaderInfo.isEmpty()) {
fabric.set(false);
exchangeNameIfDefault(selected.id, true);
} else {
@ -102,7 +102,7 @@ public class InstanceManageControls {
}
if (fabric.get()) {
ImGui.sameLine();
List<FabricVersionLoaderInfo> versions = getFabricLoaderInfo();
List<FabricVersionLoaderInfo> versions = fabricLoaderInfo;
if (ImGui.combo("Loader", fabricVersion, versions.stream().map(info -> info.loader.version).toArray(String[]::new))) {
selectedFabric = versions.get(fabricVersion.get());
}
@ -110,7 +110,7 @@ public class InstanceManageControls {
}
try {
if (originalStr != null && !originalStr.equals(getVersionInfo().id))
modifiedVersion.accept(getVersionInfo().id);
modifiedVersion.accept(versionInfo.id);
} catch (IOException e) {
Utils.LOGGER.error("Could not compare version string", e);
}

View File

@ -15,26 +15,26 @@ import java.nio.file.Files;
public class InstanceView {
public static void draw() throws IOException {
if (InstanceList.isEmpty()) {
if (InstanceList.isEmpty) {
ImGui.text("You have not yet created an instance");
ImGui.text("Use File->New Instance to do so");
return;
}
if (ImGui.beginTable("Instances", 2, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
for (Instance instance : InstanceList.ordered()) {
if (instance.isSetupLocked()) {
if (instance.isSetupLocked) {
ImGui.tableNextColumn();
ImGui.text("Setting up");
ImGui.tableNextColumn();
ImGui.text("This instance is currently being set up");
continue;
}
if (!Files.exists(instance.path().resolve("instance.json"))) {
if (!Files.exists(instance.path.resolve("instance.json"))) {
Utils.LOGGER.error("Invalid instance (doesn't contain instance.json): " + instance);
continue;
}
ImGui.tableNextColumn();
boolean runDisabled = instance.isRunningLocked();
boolean runDisabled = instance.isRunningLocked;
if (runDisabled) ImGui.beginDisabled();
if (ImGui.button(instance.toString())) {
try {
@ -46,7 +46,7 @@ public class InstanceView {
}
if (runDisabled) ImGui.endDisabled();
ImGui.tableNextColumn();
if (ImGui.button("Edit##" + instance.id())) {
if (ImGui.button("Edit##" + instance.id)) {
try {
GuiMain.open(new InstanceEditWindow(instance));
} catch (IOException e) {

View File

@ -12,13 +12,13 @@ public abstract class Tab {
protected abstract void renderInner();
public void render() {
if (canShow() && ImGui.beginTabItem(name)) {
if (isVisible && ImGui.beginTabItem(name)) {
renderInner();
ImGui.endTabItem();
}
}
protected boolean canShow() {
protected boolean isVisible() {
return true;
}
}

View File

@ -26,19 +26,19 @@ public class AddModWindow extends Window {
private ModrinthSearchResult mr = null;
private List<CurseforgeMod> cf = null;
public AddModWindow(Instance instance) throws IOException {
super(instance.getName() + " - Add Mods");
public AddModWindow(Instance instance) {
super(instance.name + " - Add Mods");
this.instance = instance;
}
private void reSearch() throws IOException {
private void reSearch() {
String query = this.query.get();
new Thread(() -> {
try {
ModrinthSearchResult ms = ModrinthApi.search(query, mrPage, instance.getGameVersion(), ModrinthProjectType.mod);
ModrinthSearchResult ms = ModrinthApi.search(query, mrPage, instance.gameVersion, ModrinthProjectType.mod);
if (!this.query.get().equals(query)) return;
mr = ms;
List<CurseforgeMod> cs = CurseforgeApi.search(instance.getGameVersion(), query, cfPage, "Popularity");
List<CurseforgeMod> cs = CurseforgeApi.search(instance.gameVersion, query, cfPage, "Popularity");
if (!this.query.get().equals(query)) return;
cf = cs;
} catch (IOException e) {
@ -71,12 +71,11 @@ public class AddModWindow extends Window {
reSearch();
}
}
if (mr != null && ImGui.beginTable("mods" + instance.id(), 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
if (mr != null && ImGui.beginTable("mods" + instance.id, 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
for (ModrinthSearchResult.ModResult mod : mr.hits) {
String modId = (mod.slug != null ? mod.slug : mod.project_id);
final String idPrefix = "local-";
if (mod.project_id.startsWith(idPrefix))
mod.project_id = mod.project_id.substring(idPrefix.length());
String projectId = mod.project_id.startsWith(idPrefix) ? mod.project_id.substring(idPrefix.length()) : mod.project_id;
//TODO detail view
ImGui.tableNextColumn();
ImGui.text(mod.title);
@ -84,22 +83,21 @@ public class AddModWindow extends Window {
ImGui.text(mod.description);
ImGui.tableNextColumn();
boolean alreadyPresent = false;
for (Mod mdsMod : instance.getMods()) {
alreadyPresent = mdsMod.getMetadata().sources.keySet().stream()
.anyMatch(s -> s instanceof ModrinthModSource ms
&& ms.getModId().equals(mod.project_id));
for (Mod mdsMod : instance.mods) {
alreadyPresent = mdsMod.metadata.sources.keySet().stream()
.anyMatch(s -> s instanceof ModrinthModSource ms && ms.modId.equals(projectId));
if (alreadyPresent)
break;
}
if (alreadyPresent) {
ImGui.text("Installed");
} else {
if (ImGui.button("Add##" + mod.project_id)) {
if (ImGui.button("Add##" + projectId)) {
ModrinthVersion stable = null;
ModrinthVersion beta = null;
ModrinthVersion latest = null;
for (ModrinthVersion version : ModrinthApi.getVersions(mod.project_id)) {
if (version.game_versions.contains(instance.getGameVersion()) && version.loaders.contains("fabric")) {
for (ModrinthVersion version : ModrinthApi.getVersions(projectId)) {
if (version.game_versions.contains(instance.gameVersion) && version.loaders.contains("fabric")) {
latest = version;
if (version.version_type == ModrinthVersion.VersionType.beta || version.version_type == ModrinthVersion.VersionType.release) {
beta = version;
@ -117,7 +115,7 @@ public class AddModWindow extends Window {
ModrinthVersion finalLatest = latest;
new Thread(() -> {
try {
ModManager.download(new ModrinthModSource(finalLatest.id), instance.modsDir().resolve((mod.slug == null ? mod.project_id : mod.slug) + ModPath.EXT_IMOD), instance.mds()).write();
ModManager.download(new ModrinthModSource(finalLatest.id), instance.modsDir.resolve((mod.slug == null ? projectId : mod.slug) + ModPath.EXT_IMOD), instance.mds).write();
} catch (IOException e) {
LauncherEnv.showError("Could not download mod", e);
}
@ -126,7 +124,7 @@ public class AddModWindow extends Window {
}
}
ImGui.sameLine();
if (ImGui.button("Web##" + mod.project_id)) {
if (ImGui.button("Web##" + projectId)) {
Utils.openWebBrowser(new URI("https://modrinth.com/mod/" + modId));
}
}
@ -150,7 +148,7 @@ public class AddModWindow extends Window {
reSearch();
}
}
if (cf != null && ImGui.beginTable("curseforge" + instance.id(), 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
if (cf != null && ImGui.beginTable("curseforge" + instance.id, 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.Borders)) {
for (CurseforgeMod mod : cf) {
//TODO detail view
ImGui.tableNextColumn();
@ -159,10 +157,9 @@ public class AddModWindow extends Window {
ImGui.text(mod.summary);
ImGui.tableNextColumn();
boolean alreadyPresent = false;
for (Mod mdsMod : instance.mds().getMods()) {
alreadyPresent = mdsMod.getMetadata().sources.keySet().stream()
.anyMatch(s -> s instanceof CurseforgeModSource ms
&& ms.getProjectId() == mod.id);
for (Mod mdsMod : instance.mds.mods) {
alreadyPresent = mdsMod.metadata.sources.keySet().stream()
.anyMatch(s -> s instanceof CurseforgeModSource ms && ms.projectId == mod.id);
if (alreadyPresent)
break;
}
@ -172,7 +169,7 @@ public class AddModWindow extends Window {
if (ImGui.button("Add##" + mod.id)) {
CurseforgeMod.LatestFileIndex latest = null;
for (CurseforgeMod.LatestFileIndex file : mod.latestFilesIndexes) {
if (file.gameVersion.equals(instance.getGameVersion())) {
if (file.gameVersion.equals(instance.gameVersion)) {
if (latest == null) latest = file;
}
}
@ -182,7 +179,7 @@ public class AddModWindow extends Window {
CurseforgeMod.LatestFileIndex finalLatest = latest;
new Thread(() -> {
try {
ModManager.download(new CurseforgeModSource(mod.id, finalLatest.fileId), instance.modsDir().resolve((mod.slug == null ? mod.id : mod.slug) + ModPath.EXT_IMOD), instance.mds()).write();
ModManager.download(new CurseforgeModSource(mod.id, finalLatest.fileId), instance.modsDir.resolve((mod.slug == null ? mod.id : mod.slug) + ModPath.EXT_IMOD), instance.mds).write();
} catch (IOException e) {
LauncherEnv.showError("Could not download mod", e);
}

View File

@ -49,7 +49,7 @@ public class GuiUtil {
LauncherEnv.showInfo("The instance was successfully created. You can now launch it using the main menu", "Successfully installed");
}, () -> {
try {
JFiles.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

@ -49,11 +49,11 @@ public class MainWindow extends Window {
}
if (ImGui.beginMenu("Account")) {
if (ImGui.menuItem("New")) GuiMain.open(new MicrosoftLoginWindow());
AuthInfo selected = AccountManager.getSelectedAccount();
List<MicrosoftAccount> accounts = AccountManager.getAccounts();
AuthInfo selected = AccountManager.selectedAccount;
List<MicrosoftAccount> accounts = AccountManager.accounts;
int accountsSize = accounts.size();
for (int i = 0; i < accountsSize; i++) {
MicrosoftAccount account = accounts.get(i);
MicrosoftAccount account = accounts[i];
if (selected.equals(account)) accountIndex.set(i);
if (ImGui.radioButton(account.minecraftUsername, accountIndex, i)) {
AccountManager.switchAccount(account);

View File

@ -32,7 +32,7 @@ public class NewInstanceWindow extends Window {
imc.nameBox("OK", name -> {
try {
GuiUtil.createInstance(new SetupStepInfo(imc.getVersionInfo(),
imc.getLoaderInfo(),
imc.loaderInfo,
name,
Steps.createProcessState()));
} catch (IOException e) {
@ -54,7 +54,7 @@ public class NewInstanceWindow extends Window {
GuiMain.open(new ProcessStateWatcherWindow("Importing", "Could not import packs", state, cToken -> {
for (Path pack : packs) {
Path imported = Importers.importPack(pack, state);
LauncherEnv.showInfo(pack.getFileName() + " has been successfully imported as " + imported.getFileName(), "Imported pack");
LauncherEnv.showInfo(pack.fileName + " has been successfully imported as " + imported.fileName, "Imported pack");
}
}, null));
}

View File

@ -36,8 +36,8 @@ public class ProcessStateWatcherWindow extends Window {
@Override
public void draw() {
ImGui.progressBar(state.getProgress());
ImGui.textUnformatted(state.getCurrentStep());
ImGui.progressBar(state.progress);
ImGui.textUnformatted(state.currentStep);
if (cancel != null && ImGui.button("Cancel")) {
canceled.set(true);
close();

View File

@ -2,12 +2,15 @@ package io.gitlab.jfronny.inceptum.imgui.window.edit;
import imgui.ImGui;
import imgui.type.ImString;
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.launcher.model.inceptum.InstanceMeta;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
public class ArgumentsTab extends Tab {
private final InstanceEditWindow window;
@ -18,28 +21,29 @@ public class ArgumentsTab extends Tab {
public ArgumentsTab(InstanceEditWindow window) {
super("Arguments");
this.window = window;
InstanceMeta meta = window.instance.meta();
if (meta.arguments == null) meta.arguments = new InstanceMeta.Arguments();
if (meta.arguments.jvm == null) meta.arguments.jvm = new LinkedList<>();
InstanceMeta meta = window.instance.meta;
if (meta.arguments == null) meta.arguments = new InstanceMeta.Arguments(new LinkedList<>(), new LinkedList<>(), new LinkedList<>());
if (meta.arguments.jvm == null) meta.arguments = meta.arguments.withJvm(new LinkedList<>());
jvm.set(String.join("\n", meta.arguments.jvm));
if (meta.arguments.client == null) meta.arguments.client = new LinkedList<>();
if (meta.arguments.client == null) meta.arguments = meta.arguments.withClient(new LinkedList<>());
client.set(String.join("\n", meta.arguments.client));
if (meta.arguments.server == null) meta.arguments.server = new LinkedList<>();
if (meta.arguments.server == null) meta.arguments = meta.arguments.withServer(new LinkedList<>());
server.set(String.join("\n", meta.arguments.server));
}
@Override
protected void renderInner() {
InstanceMeta meta = window.instance.meta;
if (ImGui.inputTextMultiline("JVM", jvm)) {
window.instance.meta().arguments.jvm = List.of(jvm.get().split("[\r\n]+"));
meta.arguments = meta.arguments.withJvm(List.of(Utils.NEW_LINE.split(jvm.get())));
window.instance.writeMeta();
}
if (ImGui.inputTextMultiline("Client", client)) {
window.instance.meta().arguments.client = List.of(client.get().split("[\r\n]+"));
meta.arguments = meta.arguments.withClient(List.of(Utils.NEW_LINE.split(client.get())));
window.instance.writeMeta();
}
if (ImGui.inputTextMultiline("Server", server)) {
window.instance.meta().arguments.server = List.of(server.get().split("[\r\n]+"));
meta.arguments = meta.arguments.withServer(List.of(Utils.NEW_LINE.split(server.get())));
window.instance.writeMeta();
}
}

View File

@ -23,18 +23,18 @@ public class ExportTab extends Tab {
@Override
protected void renderInner() {
if (window.instance.mds().isComplete()) {
if (window.instance.mds.isComplete) {
for (Exporter<?> exporter : Exporters.EXPORTERS) {
if (ImGui.button(exporter.getName())) {
if (ImGui.button(exporter.name)) {
GuiMain.open(new TextBoxWindow("Version", "Please enter the current version of your modpack", "1.0", version -> {
String defaultName = window.instance.getName() + " " + version + " (" + exporter.getName() + ")." + exporter.getFileExtension();
String filter = "*." + exporter.getFileExtension();
Path exportPath = GuiMain.saveFileDialog("Export " + exporter.getName() + " Pack", defaultName, new String[]{filter}, exporter.getName() + " packs (" + filter + ")");
String defaultName = window.instance.name + " " + version + " (" + exporter.name + ")." + exporter.fileExtension;
String filter = "*." + exporter.fileExtension;
Path exportPath = GuiMain.saveFileDialog("Export " + exporter.name + " Pack", defaultName, new String[]{filter}, exporter.name + " packs (" + filter + ")");
if (exportPath != null) {
ProcessState state = new ProcessState(Exporters.STEP_COUNT, "Initializing...");
GuiMain.open(new ProcessStateWatcherWindow("Exporting", "Could not export pack", state, cToken -> {
exporter.generate(state, window.instance, exportPath, version);
LauncherEnv.showInfo(window.instance.getName() + " has been successfully exported to " + exportPath, "Successfully exported");
LauncherEnv.showInfo(window.instance.name + " has been successfully exported to " + exportPath, "Successfully exported");
}, null));
}
}, R::nop));

View File

@ -26,7 +26,7 @@ public class GeneralTab extends Tab {
super("General");
this.window = window;
imc = new InstanceManageControls(window.instance);
String java = window.instance.meta().java;
String java = window.instance.meta.java;
customJava = new ImBoolean(java != null);
if (java != null) customJavaPath.set(java);
}
@ -34,12 +34,12 @@ public class GeneralTab extends Tab {
@Override
protected void renderInner() {
if (ImGui.button("Open Directory")) {
Utils.openFile(window.instance.path().toFile());
Utils.openFile(window.instance.path.toFile());
}
imc.nameBox("Rename", name -> {
try {
Path newPath = MetaHolder.INSTANCE_DIR.resolve(name);
Files.move(window.instance.path(), newPath);
Files.move(window.instance.path, newPath);
GuiMain.open(new InstanceEditWindow(window.instance));
window.close();
} catch (IOException e) {
@ -55,7 +55,7 @@ public class GeneralTab extends Tab {
if (ImGui.button("Delete"))
LauncherEnv.showOkCancel("This instance will be removed forever (a long time)", "Are you sure?", () -> {
try {
JFiles.deleteRecursive(window.instance.path());
JFiles.deleteRecursive(window.instance.path);
} catch (IOException e) {
LauncherEnv.showError("Could not delete the instance", e);
}
@ -63,15 +63,15 @@ public class GeneralTab extends Tab {
}, R::nop);
if (ImGui.checkbox("Custom Java", customJava)) {
if (customJava.get()) {
window.instance.meta().java = OSUtils.getJvmBinary();
customJavaPath.set(window.instance.meta().java);
window.instance.meta.java = OSUtils.jvmBinary;
customJavaPath.set(window.instance.meta.java);
} else {
window.instance.meta().java = null;
window.instance.meta.java = null;
}
window.instance.writeMeta();
}
if (customJava.get() && ImGui.inputText("Path", customJavaPath)) {
window.instance.meta().java = customJavaPath.get();
window.instance.meta.java = customJavaPath.get();
window.instance.writeMeta();
}
}

View File

@ -16,9 +16,9 @@ public class InstanceEditWindow extends Window {
protected boolean lastTabWasMods = false;
public InstanceEditWindow(Instance instance) throws IOException {
super(instance.getName() + " - Edit");
super(instance.name + " - Edit");
this.instance = instance;
this.instance.mds().start();
this.instance.mds.start();
this.tabs = List.of(
new GeneralTab(this),
new ArgumentsTab(this),
@ -29,15 +29,15 @@ public class InstanceEditWindow extends Window {
@Override
public void draw() {
if (instance.isSetupLocked()) {
if (instance.isSetupLocked) {
ImGui.text("This instance is still being set up.");
return;
}
if (instance.isRunningLocked()) {
if (instance.isRunningLocked) {
ImGui.text("This instance is running. Edits in this state will result in breakage.");
}
lastTabWasMods = false;
if (ImGui.beginTabBar("InstanceEdit" + instance.id())) {
if (ImGui.beginTabBar("InstanceEdit" + instance.id)) {
for (Tab tab : tabs) tab.render();
ImGui.endTabBar();
}

View File

@ -29,28 +29,24 @@ public class ModsTab extends Tab {
@Override
protected void renderInner() {
window.lastTabWasMods = true;
if (!Files.exists(window.instance.modsDir())) {
if (!Files.exists(window.instance.modsDir)) {
try {
Files.createDirectories(window.instance.modsDir());
Files.createDirectories(window.instance.modsDir);
} catch (IOException e) {
Utils.LOGGER.error("Could not create mods directory which was missing from this modded instance", e);
}
}
ImGui.beginChild("mods select", 200, 0);
if (ImGui.button("Add")) {
try {
GuiMain.WINDOWS.add(new AddModWindow(window.instance));
} catch (IOException e) {
Utils.LOGGER.error("Could not open window", e);
}
GuiMain.WINDOWS.add(new AddModWindow(window.instance));
}
ImGui.sameLine();
if (Files.exists(window.instance.modsDir()) && ImGui.button("Show")) {
Utils.openFile(window.instance.modsDir().toFile());
if (Files.exists(window.instance.modsDir) && ImGui.button("Show")) {
Utils.openFile(window.instance.modsDir.toFile());
}
ImGui.sameLine();
if (Files.exists(window.instance.configDir()) && ImGui.button("Configs")) {
Utils.openFile(window.instance.configDir().toFile());
if (Files.exists(window.instance.configDir) && ImGui.button("Configs")) {
Utils.openFile(window.instance.configDir.toFile());
}
try {
Set<Mod> modSet = window.instance.getMods();
@ -58,10 +54,10 @@ public class ModsTab extends Tab {
float scannedPercentage = 0;
boolean hasUnScanned = false;
for (Mod mod : modSet) {
if (window.instance.mds().hasScanned(mod)) scannedPercentage++;
if (window.instance.mds.hasScanned(mod)) scannedPercentage++;
else hasUnScanned = true;
for (Optional<ModSource> value : mod.getMetadata().sources.values()) {
if (value.isPresent()) {
for (Optional<ModSource> value : mod.metadata.sources.values()) {
if (value.isPresent) {
updatesFound = true;
break;
}
@ -78,21 +74,21 @@ public class ModsTab extends Tab {
ImGui.separator();
for (Mod mod : modSet) {
updatesFound = false;
for (Optional<ModSource> value : mod.getMetadata().sources.values()) {
updatesFound |= value.isPresent();
for (Optional<ModSource> value : mod.metadata.sources.values()) {
updatesFound |= value.isPresent;
}
if (filterUpdates.get() && !updatesFound) continue;
if (ImGui.checkbox("##" + mod.getName(), mod.isEnabled())) {
Path newSel = ModPath.toggle(mod.getMetadataPath());
if (ImGui.checkbox("##" + mod.name, mod.isEnabled)) {
Path newSel = ModPath.toggle(mod.metadataPath);
try {
Files.move(mod.getMetadataPath(), newSel);
if (mod.getMetadataPath().equals(selected)) selected = newSel;
Files.move(mod.metadataPath, newSel);
if (mod.metadataPath.equals(selected)) selected = newSel;
} catch (IOException e) {
LauncherEnv.showError("Could not change disabled state", e);
}
}
ImGui.sameLine();
if (ImGui.button(mod.getName())) selected = mod.getMetadataPath();
if (ImGui.button(mod.name)) selected = mod.metadataPath;
}
} catch (IOException e) {
Utils.LOGGER.error("Could not show mod list", e);
@ -102,24 +98,24 @@ public class ModsTab extends Tab {
ImGui.beginGroup();
if (selected == null) {
ImGui.text("Select a mod to view settings");
} else if (window.instance.mds().hasScanned(selected)) {
Mod md = window.instance.mds().get(selected);
ImGui.text(md.getName());
} else if (window.instance.mds.hasScanned(selected)) {
Mod md = window.instance.mds[selected];
ImGui.text(md.name);
ImGui.separator();
for (String s : md.getDescription()) {
for (String s : md.description) {
ImGui.text(s);
}
ImGui.separator();
Map<ModSource, Optional<ModSource>> sources = md.getMetadata().sources;
Map<ModSource, Optional<ModSource>> sources = md.metadata.sources;
ImGui.text("Sources:");
if (sources.isEmpty())
if (sources.isEmpty)
ImGui.bulletText("Local Drive");
else {
for (Map.Entry<ModSource, Optional<ModSource>> source : sources.entrySet()) {
ImGui.bulletText(source.getKey().getName());
source.getValue().ifPresent(update -> {
for (var source : sources) {
ImGui.bulletText(source.key.name);
source.value.ifPresent(update -> {
ImGui.sameLine();
if (ImGui.button("Update to " + update.getVersion())) {
if (ImGui.button("Update to " + update.version)) {
try {
selected = md.update(update);
} catch (IOException e) {
@ -130,8 +126,8 @@ public class ModsTab extends Tab {
}
}
if (ImGui.button("Delete")) {
if (!md.getMetadata().dependents.isEmpty())
LauncherEnv.showError("This mod still has the following dependent mods installed: " + String.join(", ", md.getMetadata().dependents), "Dependents present");
if (!md.metadata.dependents.isEmpty)
LauncherEnv.showError("This mod still has the following dependent mods installed: " + String.join(", ", md.metadata.dependents), "Dependents present");
else {
try {
md.delete();
@ -148,7 +144,7 @@ public class ModsTab extends Tab {
}
@Override
protected boolean canShow() {
return window.instance.isFabric();
protected boolean isVisible() {
return window.instance.isFabric;
}
}

View File

@ -1,6 +1,7 @@
plugins {
id("inceptum.library-conventions")
id("inceptum.gson-compile")
id("inceptum.manifold")
}
dependencies {

View File

@ -50,7 +50,7 @@ public class CurseforgeApi {
if (response.pagination.totalCount != 1) {
throw new FileNotFoundException("Could not find mod with slug \"" + slug + "\"");
}
return checkDistribution(response.data.get(0));
return checkDistribution(response.data[0]);
}
public static CurseforgeMod getMod(int id) throws IOException {

View File

@ -5,6 +5,7 @@ import io.gitlab.jfronny.gson.stream.JsonReader;
import io.gitlab.jfronny.inceptum.common.Net;
import io.gitlab.jfronny.inceptum.common.model.maven.ArtifactMeta;
import io.gitlab.jfronny.inceptum.launcher.model.fabric.*;
import io.gitlab.jfronny.inceptum.launcher.model.fabric.FabricVersionLoaderInfo.WithMeta.LauncherMeta.Libraries.Library;
import io.gitlab.jfronny.inceptum.launcher.model.mojang.*;
import io.gitlab.jfronny.inceptum.launcher.util.GameVersionParser;
@ -40,40 +41,45 @@ public class FabricMetaApi {
if (meta.version != 1) throw new IOException("Unsupported fabric launcherMeta version: " + meta.version);
result.mainClass = type == FabricVersionInfoType.Server ? meta.mainClass.server : meta.mainClass.client;
List<VersionInfo.Library> libs = new ArrayList<>(version.libraries);
for (FabricVersionLoaderInfo.WithMeta.LauncherMeta.Libraries.Library library : meta.libraries.common)
for (Library library : meta.libraries.common)
libs.add(convertLib(library));
if (type == FabricVersionInfoType.Client || type == FabricVersionInfoType.Both) {
for (FabricVersionLoaderInfo.WithMeta.LauncherMeta.Libraries.Library library : meta.libraries.client)
for (Library library : meta.libraries.client)
libs.add(convertLib(library));
}
if (type == FabricVersionInfoType.Server || type == FabricVersionInfoType.Both) {
for (FabricVersionLoaderInfo.WithMeta.LauncherMeta.Libraries.Library library : meta.libraries.server)
for (Library library : meta.libraries.server)
libs.add(convertLib(library));
}
var floader = new FabricVersionLoaderInfo.WithMeta.LauncherMeta.Libraries.Library();
floader.name = "net.fabricmc:fabric-loader:" + fabricVersion;
floader.url = "https://maven.fabricmc.net/";
libs.add(convertLib(floader));
floader.name = ver.intermediary.maven;
libs.add(convertLib(floader));
libs.add(convertLib(new Library(
"net.fabricmc:fabric-loader:" + fabricVersion,
"https://maven.fabricmc.net/"
)));
libs.add(convertLib(new Library(
ver.intermediary.maven,
"https://maven.fabricmc.net/"
)));
result.libraries = List.copyOf(libs);
result.id = GameVersionParser.createVersionWithFabric(version.id, fabricVersion);
return result;
}
private static VersionInfo.Library convertLib(FabricVersionLoaderInfo.WithMeta.LauncherMeta.Libraries.Library library) {
VersionInfo.Library res = new VersionInfo.Library();
res.name = library.name;
res.rules = new Rules(true);
res.natives = new HashMap<>();
res.downloads = new VersionInfo.Library.Downloads();
res.downloads.classifiers = null;
res.downloads.artifact = new VersionInfo.Library.Downloads.Artifact();
res.downloads.artifact.path = ArtifactMeta.parse(library.name).getJarPath(true);
res.downloads.artifact.size = -1;
res.downloads.artifact.sha1 = null;
res.downloads.artifact.url = library.url + res.downloads.artifact.path;
return res;
private static VersionInfo.Library convertLib(Library library) {
String path = ArtifactMeta.parse(library.name).getJarPath(true);
return new VersionInfo.Library(
new VersionInfo.Library.Downloads(
new VersionInfo.Library.Downloads.Artifact(
path,
-1,
null,
library.url + path
),
null
),
library.name,
new HashMap<>(),
new Rules(true)
);
}
public enum FabricVersionInfoType {

View File

@ -47,7 +47,7 @@ public class McApi {
case LINUX -> info.linux;
case MAC_OS -> info.macOs;
};
List<JvmInfo.Jvm> vmList = vms.get(component);
List<JvmInfo.Jvm> vmList = vms[component];
if (vmList == null)
throw new IOException("Invalid component: " + component + " (available: " + String.join(", ", vms.keySet()));
for (JvmInfo.Jvm jvm : vmList) {

View File

@ -26,7 +26,7 @@ public class AccountManager {
}
public static boolean accountMissing() {
return ACCOUNTS.isEmpty();
return ACCOUNTS.isEmpty;
}
public static List<MicrosoftAccount> getAccounts() {
@ -40,6 +40,7 @@ public class AccountManager {
public static void saveAccounts() {
try (JsonWriter w = new JsonWriter(Files.newBufferedWriter(MetaHolder.ACCOUNTS_PATH))) {
GsonPreset.Config.configure(w);
GList.write(w, ACCOUNTS, GC_MicrosoftAccount::write);
} catch (IOException e) {
Utils.LOGGER.error("Could not save accounts", e);
@ -50,6 +51,7 @@ public class AccountManager {
Utils.LOGGER.info("Loading accounts");
if (Files.exists(MetaHolder.ACCOUNTS_PATH)) {
try (JsonReader r = new JsonReader(Files.newBufferedReader(MetaHolder.ACCOUNTS_PATH))) {
GsonPreset.Config.configure(r);
ACCOUNTS.addAll(GList.read(r, GC_MicrosoftAccount::read));
} catch (IOException e) {
Utils.LOGGER.error("Could not load accounts", e);
@ -77,7 +79,7 @@ public class AccountManager {
if (ACCOUNTS.size() == 1)
switchAccount(null);
else
switchAccount(ACCOUNTS.get(0));
switchAccount(ACCOUNTS[0]);
}
ACCOUNTS.remove(account);
saveAccounts();

View File

@ -1,9 +1,9 @@
package io.gitlab.jfronny.inceptum.launcher.api.account;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.R;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.common.*;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.response.*;
import io.gitlab.jfronny.inceptum.launcher.gson.MicrosoftAccountMeta;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.*;
@ -11,13 +11,8 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.util.*;
@GSerializable(with = MicrosoftAccountMeta.class)
@GSerializable(with = MicrosoftAccountMeta.class, configure = GsonPreset.Config.class)
public class MicrosoftAccount {
/**
* Auto generated serial.
*/
private static final long serialVersionUID = 5483749902584257559L;
/**
* The username/email/id of the account.
*/
@ -60,14 +55,14 @@ public class MicrosoftAccount {
public boolean mustLogin;
public MicrosoftAccount(MicrosoftAccountMeta meta) {
this.accountId = meta.accountId();
this.minecraftUsername = meta.minecraftUsername();
this.uuid = meta.uuid();
this.accessToken = meta.accessToken();
this.oauthToken = meta.oauthToken();
this.xstsAuth = meta.xstsAuth();
this.accessTokenExpiresAt = meta.accessTokenExpiresAt();
this.mustLogin = meta.mustLogin();
this.accountId = meta.accountId;
this.minecraftUsername = meta.minecraftUsername;
this.uuid = meta.uuid;
this.accessToken = meta.accessToken;
this.oauthToken = meta.oauthToken;
this.xstsAuth = meta.xstsAuth;
this.accessTokenExpiresAt = meta.accessTokenExpiresAt;
this.mustLogin = meta.mustLogin;
}
public MicrosoftAccountMeta toMeta() {
@ -92,14 +87,14 @@ public class MicrosoftAccount {
LoginResponse loginResponse, Profile profile) {
this.oauthToken = oauthTokenResponse;
this.xstsAuth = xstsAuthResponse;
this.accessToken = loginResponse.accessToken();
this.accessToken = loginResponse.accessToken;
this.minecraftUsername = profile.name;
this.uuid = profile.id;
this.accountId = loginResponse.username();
this.accountId = loginResponse.username;
this.mustLogin = false;
this.accessTokenExpiresAt = new Date();
this.accessTokenExpiresAt.setTime(this.accessTokenExpiresAt.getTime() + (loginResponse.expiresIn() * 1000));
this.accessTokenExpiresAt.time += loginResponse.expiresIn * 1000;
}
public String getAccessToken() {
@ -152,10 +147,10 @@ public class MicrosoftAccount {
AccountManager.saveAccounts();
}
if (force || new Date().after(this.xstsAuth.notAfter())) {
if (force || new Date().after(this.xstsAuth.notAfter)) {
Utils.LOGGER.info("xsts auth expired. Attempting to get new auth");
XboxLiveAuthResponse xboxLiveAuthResponse = MicrosoftAuthAPI.getXBLToken(this.oauthToken.accessToken);
this.xstsAuth = MicrosoftAuthAPI.getXstsToken(xboxLiveAuthResponse.token());
this.xstsAuth = MicrosoftAuthAPI.getXstsToken(xboxLiveAuthResponse.token);
if (xstsAuth == null) {
mustLogin = true;
@ -168,7 +163,7 @@ public class MicrosoftAccount {
}
if (force || new Date().after(this.accessTokenExpiresAt)) {
LoginResponse loginResponse = MicrosoftAuthAPI.loginToMinecraft(this.getIdentityToken());
LoginResponse loginResponse = MicrosoftAuthAPI.loginToMinecraft(identityToken);
if (loginResponse == null) {
mustLogin = true;
@ -177,12 +172,11 @@ public class MicrosoftAccount {
return false;
}
this.accessToken = loginResponse.accessToken();
this.accountId = loginResponse.username();
this.accessToken = loginResponse.accessToken;
this.accountId = loginResponse.username;
this.accessTokenExpiresAt = new Date();
this.accessTokenExpiresAt
.setTime(this.accessTokenExpiresAt.getTime() + (loginResponse.expiresIn() * 1000));
this.accessTokenExpiresAt.time += loginResponse.expiresIn * 1000;
AccountManager.saveAccounts();
}
@ -198,7 +192,7 @@ public class MicrosoftAccount {
}
private String getIdentityToken() {
return "XBL3.0 x=" + xstsAuth.displayClaims().xui().get(0).uhs() + ";" + xstsAuth.token();
return "XBL3.0 x=" + xstsAuth.displayClaims.xui[0].uhs + ";" + xstsAuth.token;
}
public boolean ensureAccessTokenValid() {

View File

@ -1,8 +1,9 @@
package io.gitlab.jfronny.inceptum.launcher.api.account;
import io.gitlab.jfronny.commons.HttpUtils;
import io.gitlab.jfronny.inceptum.launcher.api.account.request.*;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.*;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.request.*;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.response.*;
import java.io.IOException;
import java.io.Reader;

View File

@ -2,6 +2,7 @@ package io.gitlab.jfronny.inceptum.launcher.api.account;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.LauncherEnv;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.response.*;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.*;
import net.freeutils.httpserver.HTTPServer;
import org.jetbrains.annotations.Nullable;
@ -24,33 +25,33 @@ public class MicrosoftAuthServer implements Closeable {
public void start() throws IOException {
host.addContext("/", (req, res) -> {
if (req.getParams().containsKey("error")) {
res.getHeaders().add("Content-Type", "text/plain");
if (req.params.containsKey("error")) {
res.headers.add("Content-Type", "text/plain");
res.send(500, "Error logging in. Check console for more information");
Utils.LOGGER.error("Error logging into Microsoft account: " + URLDecoder
.decode(req.getParams().get("error_description"), StandardCharsets.UTF_8));
.decode(req.params["error_description"], StandardCharsets.UTF_8));
close();
return 0;
}
if (!req.getParams().containsKey("code")) {
res.getHeaders().add("Content-Type", "text/plain");
if (!req.params.containsKey("code")) {
res.headers.add("Content-Type", "text/plain");
res.send(400, "Code is missing");
close();
return 0;
}
try {
acquireAccessToken(req.getParams().get("code"));
acquireAccessToken(req.params["code"]);
} catch (Exception e) {
Utils.LOGGER.error("Error acquiring accessToken", e);
res.getHeaders().add("Content-Type", "text/html");
res.headers.add("Content-Type", "text/html");
res.send(500, "Error logging in. Check console for more information");
close();
return 0;
}
res.getHeaders().add("Content-Type", "text/plain");
res.headers.add("Content-Type", "text/plain");
// #. {0} is the name of the launcher
res.send(200, "Login complete. You can now close this window and go back to the Launcher");
close();
@ -61,8 +62,8 @@ public class MicrosoftAuthServer implements Closeable {
}
private void addAccount(OauthTokenResponse oauthTokenResponse, XboxLiveAuthResponse xstsAuthResponse, LoginResponse loginResponse, Profile profile) {
if (this.previous != null || AccountManager.isAccountByName(loginResponse.username())) {
MicrosoftAccount account = (MicrosoftAccount) AccountManager.getAccountByName(loginResponse.username());
if (this.previous != null || AccountManager.isAccountByName(loginResponse.username)) {
MicrosoftAccount account = (MicrosoftAccount) AccountManager.getAccountByName(loginResponse.username);
if (account == null) {
return;
@ -103,16 +104,13 @@ public class MicrosoftAuthServer implements Closeable {
}
private void acquireMinecraftToken(OauthTokenResponse oauthTokenResponse, XboxLiveAuthResponse xstsAuthResponse) throws Exception {
String xblUhs = xstsAuthResponse.displayClaims().xui().get(0).uhs();
String xblXsts = xstsAuthResponse.token();
LoginResponse loginResponse = MicrosoftAuthAPI.loginToMinecraft("XBL3.0 x=" + xblUhs + ";" + xblXsts);
LoginResponse loginResponse = MicrosoftAuthAPI.loginToMinecraft("XBL3.0 x=" + xstsAuthResponse.displayClaims.xui[0].uhs + ";" + xstsAuthResponse.token);
if (loginResponse == null) {
throw new Exception("Failed to login to Minecraft");
}
Entitlements entitlements = MicrosoftAuthAPI.getEntitlements(loginResponse.accessToken());
Entitlements entitlements = MicrosoftAuthAPI.getEntitlements(loginResponse.accessToken);
if (!(entitlements.items.stream().anyMatch(i -> i.name.equalsIgnoreCase("product_minecraft"))
&& entitlements.items.stream().anyMatch(i -> i.name.equalsIgnoreCase("game_minecraft")))) {
@ -123,7 +121,7 @@ public class MicrosoftAuthServer implements Closeable {
Profile profile = null;
try {
profile = MicrosoftAuthAPI.getMcProfile(loginResponse.accessToken());
profile = MicrosoftAuthAPI.getMcProfile(loginResponse.accessToken);
} catch (Exception e) {
LauncherEnv.showError("""
No Minecraft profiles were found for this account. Have you purchased Minecraft?

View File

@ -1,7 +0,0 @@
package io.gitlab.jfronny.inceptum.launcher.api.account.request;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
@GSerializable
public record LoginRequest(String xtoken, String platform) {
}

View File

@ -3,17 +3,16 @@ package io.gitlab.jfronny.inceptum.launcher.gson;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.gson.stream.JsonReader;
import io.gitlab.jfronny.gson.stream.JsonWriter;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import io.gitlab.jfronny.inceptum.launcher.api.account.MicrosoftAccount;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.OauthTokenResponse;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.XboxLiveAuthResponse;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.response.OauthTokenResponse;
import io.gitlab.jfronny.inceptum.launcher.model.microsoft.response.XboxLiveAuthResponse;
import java.io.IOException;
import java.util.Date;
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public record MicrosoftAccountMeta(String accountId, String minecraftUsername, String uuid, String accessToken, OauthTokenResponse oauthToken, XboxLiveAuthResponse xstsAuth, Date accessTokenExpiresAt, boolean mustLogin) {
public static final long SERIAL_VERSION_UID = 5483749902584257559L;
public static void write(JsonWriter writer, MicrosoftAccount value) throws IOException {
GC_MicrosoftAccountMeta.write(writer, value == null ? null : value.toMeta());
}

View File

@ -14,25 +14,25 @@ public class ModSourceAdapter {
writer.beginObject();
if (src instanceof ModrinthModSource mo) {
writer.name("type").value("modrinth")
.name("id").value(mo.getVersionId());
.name("id").value(mo.versionId);
} else if (src instanceof DirectModSource di) {
writer.name("type").value("direct")
.name("fileName").value(di.fileName())
.name("url").value(di.url())
.name("fileName").value(di.fileName)
.name("url").value(di.url)
.name("dependencies");
writer.beginArray();
for (ModSource dependency : di.dependencies()) {
for (ModSource dependency : di.dependencies) {
write(writer, dependency);
}
writer.endArray();
} else if (src instanceof CurseforgeModSource cu) {
writer.name("type").value("curseforge");
if (cu.getShortName().matches("\\d+")) {
writer.name("projectId").value(cu.getProjectId());
if (cu.shortName.matches("\\d+")) {
writer.name("projectId").value(cu.projectId);
} else {
writer.name("project").value(cu.getShortName());
writer.name("project").value(cu.shortName);
}
writer.name("fileId").value(cu.getFileId());
writer.name("fileId").value(cu.fileId);
} else throw new RuntimeException("ModSources with the type " + src.getClass() + " are not supported");
writer.endObject();
}

View File

@ -51,7 +51,7 @@ public class RulesAdapter {
throw new JsonParseException("Unexpected action in argument: " + actionType);
}
if (hasFeatures) valid = false;
if (osName != null && !OSUtils.TYPE.getMojName().equals(osName)) valid = false;
if (osName != null && !OSUtils.TYPE.mojName.equals(osName)) valid = false;
if (osVersion != null && !System.getProperty("os.version").matches(osVersion)) valid = false;
if (actionType.equals("disallow")) valid = !valid;
}

View File

@ -1,87 +1,81 @@
package io.gitlab.jfronny.inceptum.launcher.model.curseforge;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Date;
import java.util.List;
@GSerializable
public class CurseforgeFile {
public Integer id;
public Integer gameId;
public Integer modId;
public Boolean isAvailable;
public String displayName;
public String fileName;
/* Possible values:
1=Release
2=Beta
3=Alpha*/
public Integer releaseType;
/* Possible values:
1=Processing
2=ChangesRequired
3=UnderReview
4=Approved
5=Rejected
6=MalwareDetected
7=Deleted
8=Archived
9=Testing
10=Released
11=ReadyForReview
12=Deprecated
13=Baking
14=AwaitingPublishing
15=FailedPublishing*/
public Integer fileStatus;
public List<Hash> hashes;
public Date fileDate;
public Integer fileLength;
public Long downloadCount;
public String downloadUrl;
public List<String> gameVersions;
public List<GameVersion> sortableGameVersions;
public List<Dependency> dependencies;
public Integer alternateFileId;
public Boolean isServerPack;
public Long fileFingerprint; // murmur5 hash
public List<Module> modules;
@GSerializable
public static class Hash {
public String value;
@GSerializable(configure = GsonPreset.Api.class)
public record CurseforgeFile(
int id,
int gameId,
int modId,
boolean isAvailable,
String displayName,
String fileName,
/* Possible values:
1=Sha1
2=Md5*/
public Integer algo;
}
@GSerializable
public static class GameVersion {
public String gameVersionName;
public String gameVersionPadded;
public String gameVersion;
public Date gameVersionReleaseDate;
public Integer gameVersionTypeId;
}
@GSerializable
public static class Dependency {
public Integer modId;
1=Release
2=Beta
3=Alpha*/
int releaseType,
/* Possible values:
1=EmbeddedLibrary
2=OptionalDependency
3=RequiredDependency
4=Tool
5=Incompatible
6=Include*/
public Integer relationType;
1=Processing
2=ChangesRequired
3=UnderReview
4=Approved
5=Rejected
6=MalwareDetected
7=Deleted
8=Archived
9=Testing
10=Released
11=ReadyForReview
12=Deprecated
13=Baking
14=AwaitingPublishing
15=FailedPublishing*/
int fileStatus,
List<Hash> hashes,
Date fileDate,
int fileLength,
long downloadCount,
String downloadUrl,
List<String> gameVersions,
List<GameVersion> sortableGameVersions,
List<Dependency> dependencies,
int alternateFileId,
boolean isServerPack,
long fileFingerprint, // murmur5 hash
List<Module> modules
) {
/* Possible algorithms:
1=Sha1
2=Md5*/
@GSerializable(configure = GsonPreset.Api.class)
public record Hash(String value, int algo) {
}
@GSerializable
public static class Module {
public String name;
public Long fingerprint;
@GSerializable(configure = GsonPreset.Api.class)
public record GameVersion(String gameVersionName,
String gameVersionPadded,
String gameVersion,
Date gameVersionReleaseDate,
int gameVersionTypeId) {
}
/* Possible relationship types:
1=EmbeddedLibrary
2=OptionalDependency
3=RequiredDependency
4=Tool
5=Incompatible
6=Include*/
@GSerializable(configure = GsonPreset.Api.class)
public record Dependency(int modId, int relationType) {
}
@GSerializable(configure = GsonPreset.Api.class)
public record Module(String name, long fingerprint) {
}
}

View File

@ -1,105 +1,95 @@
package io.gitlab.jfronny.inceptum.launcher.model.curseforge;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Date;
import java.util.List;
@GSerializable
public class CurseforgeMod {
public Integer id;
public Integer gameId;
public String name;
public String slug;
public Links links;
public String summary;
/* Possible values:
1=New
2=ChangesRequired
3=UnderSoftReview
4=Approved
5=Rejected
6=ChangesMade
7=Inactive
8=Abandoned
9=Deleted
10=UnderReview*/
public Integer status;
public Long downloadCount;
public Boolean isFeatured;
public Integer primaryCategoryId;
public List<Category> categories;
public Integer classId;
public List<Author> authors;
public Logo logo;
public List<Screenshot> screenshots;
public Integer mainFileId;
public List<CurseforgeFile> latestFiles;
public List<LatestFileIndex> latestFilesIndexes;
public Date dateCreated;
public Date dateModified;
public Date dateReleased;
public Boolean allowModDistribution;
public Integer gamePopularityRank;
public Boolean isAvailable;
public Integer thumbsUpCount;
@GSerializable
public static class Links {
public String websiteUrl;
public String wikiUrl;
public String issuesUrl;
public String sourcesUrl;
@GSerializable(configure = GsonPreset.Api.class)
public record CurseforgeMod(
int id,
int gameId,
String name,
String slug,
Links links,
String summary, // optional
/* Possible values:
1=New
2=ChangesRequired
3=UnderSoftReview
4=Approved
5=Rejected
6=ChangesMade
7=Inactive
8=Abandoned
9=Deleted
10=UnderReview*/
int status,
long downloadCount,
boolean isFeatured,
int primaryCategoryId,
List<Category> categories,
int classId,
List<Author> authors,
Logo logo,
List<Screenshot> screenshots,
int mainFileId,
List<CurseforgeFile> latestFiles,
List<LatestFileIndex> latestFilesIndexes,
Date dateCreated,
Date dateModified,
Date dateReleased,
boolean allowModDistribution,
int gamePopularityRank,
boolean isAvailable,
int thumbsUpCount
) {
@GSerializable(configure = GsonPreset.Api.class)
public record Links(String websiteUrl, String wikiUrl, String issuesUrl, String sourcesUrl) {
}
@GSerializable
public static class Category {
public Integer id;
public Integer gameId;
public String name;
public String slug;
public String url;
public String iconUrl;
public Date dateModified;
public Boolean isClass;
public Integer classId;
public Integer primaryCategoryId;
@GSerializable(configure = GsonPreset.Api.class)
public record Category(int id,
int gameId,
String name,
String slug,
String url,
String iconUrl,
Date dateModified,
boolean isClass,
int classId,
int primaryCategoryId) {
}
@GSerializable
public static class Author {
public Integer id;
public String name;
public String url;
@GSerializable(configure = GsonPreset.Api.class)
public record Author(int id, String name, String url) {
}
@GSerializable
public static class Logo {
public Integer id;
public Integer modId;
public String title;
public String description;
public String thumbnailUrl;
public String url;
@GSerializable(configure = GsonPreset.Api.class)
public record Logo(int id,
int modId,
String title,
String description,
String thumbnailUrl,
String url) {
}
@GSerializable
public static class Screenshot {
public Integer id;
public Integer modId;
public String title;
public String description;
public String thumbnailUrl;
public String url;
@GSerializable(configure = GsonPreset.Api.class)
public record Screenshot(int id,
int modId,
String title,
String description,
String thumbnailUrl,
String url) {
}
@GSerializable
public static class LatestFileIndex {
public String gameVersion;
public Integer fileId;
public String filename;
public Integer releaseType;
public Integer gameVersionTypeId;
public Integer modLoader;
@GSerializable(configure = GsonPreset.Api.class)
public record LatestFileIndex(String gameVersion,
int fileId,
String filename,
int releaseType,
int gameVersionTypeId,
Integer modLoader) {
}
}

View File

@ -1,36 +1,27 @@
package io.gitlab.jfronny.inceptum.launcher.model.curseforge;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Set;
@GSerializable
public class CurseforgeModpackManifest {
public Minecraft minecraft;
public String manifestType;
public Integer manifestVersion;
public String name;
public String version;
public String author;
public Set<File> files;
public String overrides;
@GSerializable
public static class Minecraft {
public String version;
public Set<ModLoader> modLoaders;
@GSerializable
public static class ModLoader {
public String id;
public Boolean primary;
@GSerializable(configure = GsonPreset.Api.class)
public record CurseforgeModpackManifest(Minecraft minecraft,
String manifestType,
int manifestVersion,
String name,
String version,
String author,
Set<File> files,
String overrides) {
@GSerializable(configure = GsonPreset.Api.class)
public record Minecraft(String version, Set<ModLoader> modLoaders) {
@GSerializable(configure = GsonPreset.Api.class)
public record ModLoader(String id, boolean primary) {
}
}
@GSerializable
public static class File {
public Integer projectID;
public Integer fileID;
public Boolean required;
@GSerializable(configure = GsonPreset.Api.class)
public record File(int projectID, int fileID, boolean required) {
}
}

View File

@ -1,28 +1,22 @@
package io.gitlab.jfronny.inceptum.launcher.model.curseforge.response;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.CurseforgeFile;
import java.util.List;
@GSerializable
public class FingerprintMatchesResponse {
public Result data;
@GSerializable
public static class Result {
public Boolean isCacheBuilt;
public List<Match> exactMatches;
public List<Integer> exactFingerprints;
public List<Match> partialMatches;
public List<Integer> installedFingerprints;
public List<Integer> unmatchedFingerprints;
@GSerializable
public static class Match {
public Integer id;
public CurseforgeFile file;
public List<CurseforgeFile> latestFiles;
@GSerializable(configure = GsonPreset.Api.class)
public record FingerprintMatchesResponse(Result data) {
@GSerializable(configure = GsonPreset.Api.class)
public record Result(boolean isCacheBuilt,
List<Match> exactMatches,
List<Integer> exactFingerprints,
List<Match> partialMatches,
List<Integer> installedFingerprints,
List<Integer> unmatchedFingerprints) {
@GSerializable(configure = GsonPreset.Api.class)
public record Match(int id, CurseforgeFile file, List<CurseforgeFile> latestFiles) {
}
}
}

View File

@ -1,9 +1,9 @@
package io.gitlab.jfronny.inceptum.launcher.model.curseforge.response;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.CurseforgeFile;
@GSerializable
public class GetModFileResponse {
public CurseforgeFile data;
@GSerializable(configure = GsonPreset.Api.class)
public record GetModFileResponse(CurseforgeFile data) {
}

View File

@ -1,9 +1,9 @@
package io.gitlab.jfronny.inceptum.launcher.model.curseforge.response;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.CurseforgeMod;
@GSerializable
public class GetModResponse {
public CurseforgeMod data;
@GSerializable(configure = GsonPreset.Api.class)
public record GetModResponse(CurseforgeMod data) {
}

View File

@ -1,20 +1,14 @@
package io.gitlab.jfronny.inceptum.launcher.model.curseforge.response;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import io.gitlab.jfronny.inceptum.launcher.model.curseforge.CurseforgeMod;
import java.util.List;
@GSerializable
public class SearchResponse {
public List<CurseforgeMod> data;
public Pagination pagination;
@GSerializable
public static class Pagination {
public Integer index;
public Integer pageSite;
public Integer resultCount;
public Integer totalCount;
@GSerializable(configure = GsonPreset.Api.class)
public record SearchResponse(List<CurseforgeMod> data, Pagination pagination) {
@GSerializable(configure = GsonPreset.Api.class)
public record Pagination(int index, int pageSite, int resultCount, int totalCount) {
}
}

View File

@ -1,12 +1,8 @@
package io.gitlab.jfronny.inceptum.launcher.model.fabric;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
@GSerializable
public class FabricLoaderVersion {
public String separator;
public Integer build;
public String maven;
public String version;
public Boolean stable;
@GSerializable(configure = GsonPreset.Api.class)
public record FabricLoaderVersion(String separator, int build, String maven, String version, boolean stable) {
}

View File

@ -1,11 +1,8 @@
package io.gitlab.jfronny.inceptum.launcher.model.fabric;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
@GSerializable
public class FabricModJson {
public String id;
public String name;
public String description;
public String version;
@GSerializable(configure = GsonPreset.Api.class)
public record FabricModJson(String id, String name, String description, String version) {
}

View File

@ -1,41 +1,30 @@
package io.gitlab.jfronny.inceptum.launcher.model.fabric;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.List;
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public class FabricVersionLoaderInfo {
public FabricLoaderVersion loader;
public IntermediaryVersion intermediary;
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public static class WithMeta extends FabricVersionLoaderInfo {
public LauncherMeta launcherMeta;
@GSerializable
public static class LauncherMeta {
public int version;
public Libraries libraries;
public MainClass mainClass;
@GSerializable
public static class Libraries {
public List<Library> client;
public List<Library> common;
public List<Library> server;
@GSerializable
public static class Library {
public String name;
public String url;
@GSerializable(configure = GsonPreset.Api.class)
public record LauncherMeta(int version, Libraries libraries, MainClass mainClass) {
@GSerializable(configure = GsonPreset.Api.class)
public record Libraries(List<Library> client, List<Library> common, List<Library> server) {
@GSerializable(configure = GsonPreset.Api.class)
public record Library(String name, String url) {
}
}
@GSerializable
public static class MainClass {
public String client;
public String server;
@GSerializable(configure = GsonPreset.Api.class)
public record MainClass(String client, String server) {
}
}
}

View File

@ -1,10 +1,8 @@
package io.gitlab.jfronny.inceptum.launcher.model.fabric;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
@GSerializable
public class IntermediaryVersion {
public String maven;
public String version;
public boolean stable;
@GSerializable(configure = GsonPreset.Api.class)
public record IntermediaryVersion(String maven, String version, boolean stable) {
}

View File

@ -2,18 +2,8 @@ package io.gitlab.jfronny.inceptum.launcher.model.inceptum;
import io.gitlab.jfronny.inceptum.launcher.model.mojang.VersionInfo;
public class ArtifactInfo {
public final String path;
public final String sha1;
public final int size;
public final String url;
public final boolean isNative;
public record ArtifactInfo(String path, String sha1, int size, String url, boolean isNative) {
public ArtifactInfo(VersionInfo.Library.Downloads.Artifact artifact, boolean isNative) {
path = artifact.path;
sha1 = artifact.sha1;
size = artifact.size;
url = artifact.url;
this.isNative = isNative;
this(artifact.path, artifact.sha1, artifact.size, artifact.url, isNative);
}
}

View File

@ -1,6 +1,7 @@
package io.gitlab.jfronny.inceptum.launcher.model.inceptum;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.List;
import java.util.Objects;
@ -14,42 +15,37 @@ public class InstanceMeta {
public Long lastLaunched;
public Arguments arguments;
@GSerializable
public static class Arguments {
public List<String> jvm;
public List<String> client;
public List<String> server;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Arguments arguments = (Arguments) o;
return Objects.equals(jvm, arguments.jvm)
&& Objects.equals(client, arguments.client)
&& Objects.equals(server, arguments.server);
}
@Override
public int hashCode() {
return Objects.hash(jvm, client, server);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InstanceMeta that = (InstanceMeta) o;
return Objects.equals(version, that.version)
&& Objects.equals(java, that.java)
&& Objects.equals(minMem, that.minMem)
&& Objects.equals(maxMem, that.maxMem)
&& Objects.equals(arguments, that.arguments);
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (InstanceMeta) obj;
return Objects.equals(this.version, that.version) &&
Objects.equals(this.java, that.java) &&
Objects.equals(this.minMem, that.minMem) &&
Objects.equals(this.maxMem, that.maxMem) &&
Objects.equals(this.lastLaunched, that.lastLaunched) &&
Objects.equals(this.arguments, that.arguments);
}
@Override
public int hashCode() {
return Objects.hash(version, java, minMem, maxMem, arguments);
return Objects.hash(version, java, minMem, maxMem, lastLaunched, arguments);
}
@GSerializable(configure = GsonPreset.Config.class)
public record Arguments(List<String> jvm, List<String> client, List<String> server) {
public Arguments withJvm(List<String> jvm) {
return new Arguments(jvm, client, server);
}
public Arguments withClient(List<String> client) {
return new Arguments(jvm, client, server);
}
public Arguments withServer(List<String> server) {
return new Arguments(jvm, client, server);
}
}
}

View File

@ -1,6 +1,7 @@
package io.gitlab.jfronny.inceptum.launcher.model.inceptum;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import io.gitlab.jfronny.inceptum.launcher.gson.ModMetaSourcesAdapter;
import io.gitlab.jfronny.inceptum.launcher.system.source.ModSource;
import org.jetbrains.annotations.NotNull;
@ -8,7 +9,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
@GSerializable(with = ModMetaSourcesAdapter.class)
@GSerializable(with = ModMetaSourcesAdapter.class, configure = GsonPreset.Config.class)
public class ModMeta$Sources implements Map<ModSource, Optional<ModSource>> {
private Map<ModSource, Optional<ModSource>> delegate = new LinkedHashMap<>();
@ -34,7 +35,7 @@ public class ModMeta$Sources implements Map<ModSource, Optional<ModSource>> {
@Override
public Optional<ModSource> get(Object o) {
return delegate.get(o);
return delegate[o];
}
@Nullable

View File

@ -3,6 +3,7 @@ package io.gitlab.jfronny.inceptum.launcher.model.inceptum;
import io.gitlab.jfronny.commons.HashUtils;
import io.gitlab.jfronny.gson.compile.annotations.GPrefer;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import io.gitlab.jfronny.inceptum.common.Utils;
import io.gitlab.jfronny.inceptum.launcher.api.CurseforgeApi;
import io.gitlab.jfronny.inceptum.launcher.api.ModrinthApi;
@ -17,17 +18,52 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
@GSerializable
public class ModMeta {
public ModMeta$Sources sources; //key: source, value: update
public String sha1;
public Long murmur2;
public List<String> dependents; // by file name
public List<String> dependencies; // by file name
public boolean explicit = true;
@GSerializable(configure = GsonPreset.Config.class)
public record ModMeta(
ModMeta$Sources sources, //key: source, value: update
String sha1,
Long murmur2,
List<String> dependents, // by file name
List<String> dependencies, // by file name
boolean explicit
) {
@GPrefer
public ModMeta() {
public ModMeta {}
public static ModMeta of(Path mod) {
String sha1 = null;
Long murmur2 = null;
if (!Files.isDirectory(mod)) {
try {
byte[] data = Files.readAllBytes(mod);
sha1 = HashUtils.sha1(data);
murmur2 = HashUtils.murmur2(data);
} catch (IOException e) {
Utils.LOGGER.error("Could not read file hash", e);
}
}
return new ModMeta(
new ModMeta$Sources(),
sha1,
murmur2,
new ArrayList<>(),
new ArrayList<>(),
true
);
}
public static ModMeta of(String sha1, Long murmur2, @Nullable ModSource knownSource, String gameVersion) {
ModMeta res = new ModMeta(
new ModMeta$Sources(),
sha1,
murmur2,
new ArrayList<>(),
new ArrayList<>(),
true
);
if (knownSource != null) res.addSource(knownSource, gameVersion);
res.initialize(gameVersion);
return res;
}
public boolean initialize(String gameVersion) {
@ -50,7 +86,8 @@ public class ModMeta {
if (!curseforge) {
try {
FingerprintMatchesResponse.Result cf = CurseforgeApi.checkFingerprint(murmur2);
if (!cf.exactMatches.isEmpty()) {
if (!cf.exactMatches.isEmpty) {
// TODO use array access once fixed
FingerprintMatchesResponse.Result.Match f = cf.exactMatches.get(0);
addSource(new CurseforgeModSource(f.id, f.file.id), gameVersion);
changed = true;
@ -62,40 +99,12 @@ public class ModMeta {
return changed;
}
public static ModMeta of(Path mod) {
ModMeta res = new ModMeta();
res.sources = new ModMeta$Sources();
if (!Files.isDirectory(mod)) {
try {
byte[] data = Files.readAllBytes(mod);
res.sha1 = HashUtils.sha1(data);
res.murmur2 = HashUtils.murmur2(data);
} catch (IOException e) {
Utils.LOGGER.error("Could not read file hash", e);
}
}
res.dependents = new ArrayList<>();
res.dependencies = new ArrayList<>();
return res;
}
public static ModMeta of(String sha1, Long murmur2, @Nullable ModSource knownSource, String gameVersion) {
ModMeta res = new ModMeta();
res.sources = new ModMeta$Sources();
res.sha1 = sha1;
res.murmur2 = murmur2;
res.dependents = new ArrayList<>();
res.dependencies = new ArrayList<>();
if (knownSource != null) res.addSource(knownSource, gameVersion);
res.initialize(gameVersion);
return res;
}
public void addSource(ModSource source, String gameVersion) {
try {
// TODO use array access once fixed
sources.put(source, source.getUpdate(gameVersion));
} catch (IOException e) {
Utils.LOGGER.error("Could not check " + source.getName() + " for updates", e);
Utils.LOGGER.error("Could not check " + source.name + " for updates", e);
}
}
}

View File

@ -1,17 +1,13 @@
package io.gitlab.jfronny.inceptum.launcher.model.microsoft;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.List;
@GSerializable
public class Entitlements {
public List<StoreItem> items;
public String signature;
@GSerializable
public static class StoreItem {
public String name;
public String signature;
@GSerializable(configure = GsonPreset.Api.class)
public record Entitlements(List<StoreItem> items, String signature) {
@GSerializable(configure = GsonPreset.Api.class)
public record StoreItem(String name, String signature) {
}
}

View File

@ -1,48 +0,0 @@
package io.gitlab.jfronny.inceptum.launcher.model.microsoft;
import io.gitlab.jfronny.gson.annotations.SerializedName;
import io.gitlab.jfronny.gson.compile.annotations.GPrefer;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import java.util.Date;
@GSerializable
public class OauthTokenResponse {
@SerializedName("token_type")
public String tokenType;
@SerializedName("expires_in")
public Integer expiresIn;
@SerializedName("expires_at")
public Date expiresAt;
public String scope;
@SerializedName("access_token")
public String accessToken;
@SerializedName("refresh_token")
public String refreshToken;
@SerializedName("user_id")
public String userId;
public String foci;
@GPrefer
public OauthTokenResponse(String tokenType, Integer expiresIn, Date expiresAt, String scope, String accessToken, String refreshToken, String userId, String foci) {
this.tokenType = tokenType;
this.expiresIn = expiresIn;
this.expiresAt = expiresAt;
this.scope = scope;
this.accessToken = accessToken;
this.refreshToken = refreshToken;
this.userId = userId;
this.foci = foci;
if (this.expiresAt == null) {
this.expiresAt = new Date();
this.expiresAt.setTime(this.expiresAt.getTime() + this.expiresIn * 1000);
}
}
}

View File

@ -1,27 +1,17 @@
package io.gitlab.jfronny.inceptum.launcher.model.microsoft;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.List;
@GSerializable
public class Profile {
public String id;
public String name;
public List<Skin> skins;
public List<Cape> capes;
@GSerializable
public static class Skin {
public String id;
public String state;
public String url;
public String variant;
public String alias;
@GSerializable(configure = GsonPreset.Api.class)
public record Profile(String id, String name, List<Skin> skins, List<Cape> capes) {
@GSerializable(configure = GsonPreset.Api.class)
public record Skin(String id, String state, String url, String variant, String alias) {
}
@GSerializable
public static class Cape {
public String id;
@GSerializable(configure = GsonPreset.Api.class)
public record Cape(String id) {
}
}

View File

@ -0,0 +1,8 @@
package io.gitlab.jfronny.inceptum.launcher.model.microsoft.request;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
@GSerializable(configure = GsonPreset.Api.class)
public record LoginRequest(String xtoken, String platform) {
}

View File

@ -1,13 +1,14 @@
package io.gitlab.jfronny.inceptum.launcher.api.account.request;
package io.gitlab.jfronny.inceptum.launcher.model.microsoft.request;
import io.gitlab.jfronny.gson.annotations.SerializedName;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public record XblTokenRequest(@SerializedName("Properties") Properties properties,
@SerializedName("RelyingParty") String relyingParty,
@SerializedName("TokenType") String tokenType) {
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public record Properties(@SerializedName("AuthMethod") String authMethod,
@SerializedName("SiteName") String siteName,
@SerializedName("RpsTicket") String rpsTicket) {

View File

@ -1,15 +1,16 @@
package io.gitlab.jfronny.inceptum.launcher.api.account.request;
package io.gitlab.jfronny.inceptum.launcher.model.microsoft.request;
import io.gitlab.jfronny.gson.annotations.SerializedName;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.List;
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public record XstsTokenRequest(@SerializedName("Properties") Properties properties,
@SerializedName("RelyingParty") String relyingParty,
@SerializedName("TokenType") String tokenType) {
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public record Properties(@SerializedName("SandboxId") String sandboxId, @SerializedName("UserTokens") List<String> userTokens) {
}
}

View File

@ -1,10 +1,10 @@
package io.gitlab.jfronny.inceptum.launcher.model.microsoft;
package io.gitlab.jfronny.inceptum.launcher.model.microsoft.response;
import io.gitlab.jfronny.gson.annotations.SerializedName;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
//TODO test SerializedName
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public record LoginResponse(String username,
@SerializedName("access_token") String accessToken,
@SerializedName("token_type") String tokenType,

View File

@ -0,0 +1,39 @@
package io.gitlab.jfronny.inceptum.launcher.model.microsoft.response;
import io.gitlab.jfronny.gson.annotations.SerializedName;
import io.gitlab.jfronny.gson.compile.annotations.GPrefer;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Date;
@GSerializable(configure = GsonPreset.Api.class)
public record OauthTokenResponse(
@SerializedName("token_type") String tokenType,
@SerializedName("expires_in") int expiresIn,
@SerializedName("expires_at") Date expiresAt,
String scope,
@SerializedName("access_token") String accessToken,
@SerializedName("refresh_token") String refreshToken,
@SerializedName("user_id") String userId,
String foci) {
@GPrefer
public OauthTokenResponse(String tokenType, int expiresIn, Date expiresAt, String scope, String accessToken, String refreshToken, String userId, String foci) {
this.tokenType = tokenType;
this.expiresIn = expiresIn;
this.expiresAt = getExpiresAt(expiresAt, expiresIn);
this.scope = scope;
this.accessToken = accessToken;
this.refreshToken = refreshToken;
this.userId = userId;
this.foci = foci;
}
private static Date getExpiresAt(Date expiresAt, long expiresIn) {
if (expiresAt == null) {
expiresAt = new Date();
expiresAt.time += expiresIn * 1000;
}
return expiresAt;
}
}

View File

@ -1,20 +1,20 @@
package io.gitlab.jfronny.inceptum.launcher.model.microsoft;
package io.gitlab.jfronny.inceptum.launcher.model.microsoft.response;
import io.gitlab.jfronny.gson.annotations.SerializedName;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Date;
import java.util.List;
//TODO test SerializedName
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public record XboxLiveAuthResponse(@SerializedName("IssueInstant") Date issueInstant,
@SerializedName("NotAfter") Date notAfter,
@SerializedName("Token") String token,
@SerializedName("DisplayClaims") DisplayClaims displayClaims) {
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public record DisplayClaims(List<XUIClaim> xui) {
@GSerializable
@GSerializable(configure = GsonPreset.Api.class)
public record XUIClaim(String uhs) {
}
}

View File

@ -1,9 +1,8 @@
package io.gitlab.jfronny.inceptum.launcher.model.modrinth;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
@GSerializable
public class ModrinthHashes { //TODO ensure this can parse with additional hashes
public String sha1;
public String sha512;
@GSerializable(configure = GsonPreset.Api.class)
public record ModrinthHashes(String sha1, String sha512) {
}

View File

@ -2,39 +2,33 @@ package io.gitlab.jfronny.inceptum.launcher.model.modrinth;
import io.gitlab.jfronny.gson.annotations.SerializedName;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import org.jetbrains.annotations.Nullable;
import java.util.List;
@GSerializable
public class ModrinthModpackManifest {
public Integer formatVersion; // 1
public String game; // "minecraft"
public String versionId;
public String name;
public String summary; // optional
public List<File> files;
public Dependencies dependencies;
@GSerializable
public static class File {
public String path;
public ModrinthHashes hashes;
public Env env; // optional
public List<String> downloads;
public Long fileSize;
@GSerializable
public static class Env {
public ModrinthDependencyType client;
public ModrinthDependencyType server;
@GSerializable(configure = GsonPreset.Api.class)
public record ModrinthModpackManifest(
int formatVersion, // 1
String game, // "minecraft"
String versionId,
String name,
String summary,
List<File> files,
Dependencies dependencies
) {
@GSerializable(configure = GsonPreset.Api.class)
public record File(String path, ModrinthHashes hashes, @Nullable Env env, List<String> downloads, long fileSize) {
@GSerializable(configure = GsonPreset.Api.class)
public record Env(ModrinthDependencyType client, ModrinthDependencyType server) {
}
}
@GSerializable
public static class Dependencies { // All are nullable
public String minecraft;
public String forge;
@SerializedName("fabric-loader") public String fabricLoader;
@SerializedName("quilt-loader") public String quiltLoader;
// All are nullable
@GSerializable(configure = GsonPreset.Api.class)
public record Dependencies(String minecraft,
String forge,
@SerializedName("fabric-loader") String fabricLoader,
@SerializedName("quilt-loader") String quiltLoader) {
}
}

View File

@ -1,58 +1,48 @@
package io.gitlab.jfronny.inceptum.launcher.model.modrinth;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Date;
import java.util.List;
@GSerializable
public class ModrinthProject {
public String id;
public String slug;
public ModrinthProjectType project_type;
public String team;
public String title;
public String description;
public String body;
public String body_url;
public Date publish;
public Date updated;
public String status;
public License license;
public ModrinthDependencyType client_side;
public ModrinthDependencyType server_side;
public Long downloads;
public Long follows;
public List<String> categories;
public List<String> versions;
public String icon_url;
public String issues_url;
public String source_url;
public String wiki_url;
public String discord_url;
public List<DonationUrl> donation_urls;
public List<GalleryItem> gallery;
@GSerializable
public static class DonationUrl {
public String id;
public String platform;
public String url;
@GSerializable(configure = GsonPreset.Api.class)
public record ModrinthProject(
String id,
String slug,
ModrinthProjectType project_type,
String team,
String title,
String description,
String body,
String body_url,
Date publish,
Date updated,
String status,
License license,
ModrinthDependencyType client_side,
ModrinthDependencyType server_side,
long downloads,
long follows,
List<String> categories,
List<String> versions,
String icon_url,
String issues_url,
String source_url,
String wiki_url,
String discord_url,
List<DonationUrl> donation_urls,
List<GalleryItem> gallery
) {
@GSerializable(configure = GsonPreset.Api.class)
public record DonationUrl(String id, String platform, String url) {
}
@GSerializable
public static class License {
public String id;
public String name;
public String url;
@GSerializable(configure = GsonPreset.Api.class)
public record License(String id, String name, String url) {
}
@GSerializable
public static class GalleryItem {
public String url;
public Boolean featured;
public String title;
public String description;
public Date created;
@GSerializable(configure = GsonPreset.Api.class)
public record GalleryItem(String url, boolean featured, String title, String description, Date created) {
}
}

View File

@ -1,36 +1,33 @@
package io.gitlab.jfronny.inceptum.launcher.model.modrinth;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Date;
import java.util.List;
@GSerializable
public class ModrinthSearchResult {
public List<ModResult> hits;
public Integer offset;
public Integer limit;
public Integer total_hits;
@GSerializable
public static class ModResult {
public String project_id;
public ModrinthProjectType project_type;
public String slug;
public String author;
public String title;
public String description;
public List<String> categories;
public List<String> versions;
public Long downloads;
public Long follows;
public String icon_url;
public Date date_created;
public Date date_modified;
public String latest_version;
public String license;
public String client_side;
public String server_side;
public List<String> gallery;
@GSerializable(configure = GsonPreset.Api.class)
public record ModrinthSearchResult(List<ModResult> hits, int offset, int limit, int total_hits) {
@GSerializable(configure = GsonPreset.Api.class)
public record ModResult(
String project_id,
ModrinthProjectType project_type,
String slug,
String author,
String title,
String description,
List<String> categories,
List<String> versions,
long downloads,
long follows,
String icon_url,
Date date_created,
Date date_modified,
String latest_version,
String license,
String client_side,
String server_side,
List<String> gallery
) {
}
}

View File

@ -1,46 +1,39 @@
package io.gitlab.jfronny.inceptum.launcher.model.modrinth;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Date;
import java.util.List;
@GSerializable
public class ModrinthVersion {
public String id;
public String project_id;
public String author_id;
public Boolean featured;
public String name;
public String version_number;
public String changelog;
public String changelog_url;
public Date date_published;
public Long downloads;
public VersionType version_type;
public List<File> files;
public List<Dependency> dependencies;
public List<String> game_versions;
public List<String> loaders;
@GSerializable(configure = GsonPreset.Api.class)
public record ModrinthVersion(
String id,
String project_id,
String author_id,
boolean featured,
String name,
String version_number,
String changelog,
String changelog_url,
Date date_published,
long downloads,
VersionType version_type,
List<File> files,
List<Dependency> dependencies,
List<String> game_versions,
List<String> loaders
) {
public enum VersionType {
alpha, beta, release
}
@GSerializable
public static class File {
public ModrinthHashes hashes;
public String url;
public String filename;
public Boolean primary;
@GSerializable(configure = GsonPreset.Api.class)
public record File(ModrinthHashes hashes, String url, String filename, boolean primary) {
}
@GSerializable
public static class Dependency {
public String version_id;
public String project_id;
public DependencyType dependency_type;
@GSerializable(configure = GsonPreset.Api.class)
public record Dependency(String version_id, String project_id, DependencyType dependency_type) {
public enum DependencyType {
required,
optional,

View File

@ -1,16 +1,13 @@
package io.gitlab.jfronny.inceptum.launcher.model.mojang;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Map;
@GSerializable
public class AssetIndex {
public Map<String, Asset> objects;
@GSerializable
public static class Asset {
public String hash;
public int size;
@GSerializable(configure = GsonPreset.Api.class)
public record AssetIndex(Map<String, Asset> objects) {
@GSerializable(configure = GsonPreset.Api.class)
public record Asset(String hash, int size) {
}
}

View File

@ -1,23 +1,16 @@
package io.gitlab.jfronny.inceptum.launcher.model.mojang;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.Map;
@GSerializable
public class JvmFileInfo {
public Map<String, File> files;
@GSerializable
public static class File {
public Downloads downloads;
public boolean executable;
public String type;
@GSerializable
public static class Downloads {
public MojangFileDownload lzma;
public MojangFileDownload raw;
@GSerializable(configure = GsonPreset.Api.class)
public record JvmFileInfo(Map<String, File> files) {
@GSerializable(configure = GsonPreset.Api.class)
public record File(Downloads downloads, boolean executable, String type) {
@GSerializable(configure = GsonPreset.Api.class)
public record Downloads(MojangFileDownload lzma, MojangFileDownload raw) {
}
}
}

View File

@ -2,34 +2,23 @@ package io.gitlab.jfronny.inceptum.launcher.model.mojang;
import io.gitlab.jfronny.gson.annotations.SerializedName;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import java.util.List;
import java.util.Map;
@GSerializable
public class JvmInfo {
public Map<String, List<Jvm>> linux;
@SerializedName("mac-os")
public Map<String, List<Jvm>> macOs;
@SerializedName("windows-x64")
public Map<String, List<Jvm>> windowsX64;
@GSerializable
public static class Jvm {
public Availability availability;
public MojangFileDownload manifest;
public Version version;
@GSerializable
public static class Availability {
public int group;
public int progress;
@GSerializable(configure = GsonPreset.Api.class)
public record JvmInfo(Map<String, List<Jvm>> linux,
@SerializedName("mac-os") Map<String, List<Jvm>> macOs,
@SerializedName("windows-x64") Map<String, List<Jvm>> windowsX64) {
@GSerializable(configure = GsonPreset.Api.class)
public record Jvm(Availability availability, MojangFileDownload manifest, Version version) {
@GSerializable(configure = GsonPreset.Api.class)
public record Availability(int group, int progress) {
}
@GSerializable
public static class Version {
public String name;
public String released;
@GSerializable(configure = GsonPreset.Api.class)
public record Version(String name, String released) {
}
}
}

View File

@ -1,12 +1,13 @@
package io.gitlab.jfronny.inceptum.launcher.model.mojang;
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
import io.gitlab.jfronny.inceptum.common.GsonPreset;
import io.gitlab.jfronny.inceptum.launcher.gson.MinecraftArgumentAdapter;
import java.util.LinkedHashSet;
import java.util.Set;
@GSerializable(with = MinecraftArgumentAdapter.class)
@GSerializable(with = MinecraftArgumentAdapter.class, configure = GsonPreset.Api.class)
public record MinecraftArgument(Set<String> arg) implements Cloneable {
@Override
protected MinecraftArgument clone() {

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