Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 4 additions & 20 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import java.net.URI

plugins {
java
`java-library`
`maven-publish`
// application
// application

id("net.kyori.blossom") version "1.3.1"
id("com.diffplug.spotless") version "6.19.0"
Expand All @@ -31,10 +30,6 @@ repositories {
}
}

sourceSets {
create("java8")
}

dependencies {
implementation("org.quiltmc.parsers:json:0.2.1")
compileOnly("org.jetbrains:annotations:20.1.0")
Expand All @@ -52,25 +47,16 @@ blossom {
replaceToken("__INSTALLER_VERSION", project.version)
}

tasks.compileJava {
options.release.set(17)
}
// Use this instead of compile task args cause this autoconfigures IDEs as well
java.sourceCompatibility = JavaVersion.VERSION_1_8
java.targetCompatibility = JavaVersion.VERSION_1_8

tasks.getByName("compileJava8Java", JavaCompile::class) {
options.release.set(8)
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
// Cannot use application for the time being because shadow does not like mainClass being set for some reason.
// There is a PR which has fixed this, so update shadow probably when 6.10.1 or 6.11 is out
//application {
// mainClass.set("org.quiltmc.installer.Main")
//}

tasks.jar.get().dependsOn(tasks["compileJava8Java"])
tasks.jar {
manifest {
attributes["Implementation-Title"] = "Ornithe-Installer"
Expand All @@ -88,7 +74,6 @@ tasks.shadowJar {
// Compiler does not know which set method we are targeting with null value
val classifier: String? = null;
archiveClassifier.set(classifier)
from(sourceSets["java8"].output)
}

tasks.assemble {
Expand All @@ -110,7 +95,6 @@ val copyForNative = tasks.register<Copy>("copyForNative") {
}
}


publishing {
publications {
if (env["TARGET"] == null) {
Expand Down
6 changes: 0 additions & 6 deletions src/main/java/module-info.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.quiltmc.installer;

import java.util.HashSet;
import java.util.Set;

import org.quiltmc.installer.OrnitheMeta.Endpoint;
Expand All @@ -25,7 +26,7 @@ public class IntermediaryGenerations {
static {
try {
Endpoint<int[]> endpoint = OrnitheMeta.intermediaryGenerationsEndpoint();
OrnitheMeta meta = OrnitheMeta.create(OrnitheMeta.ORNITHE_META_URL, Set.of(endpoint)).get();
OrnitheMeta meta = OrnitheMeta.create(OrnitheMeta.ORNITHE_META_URL, new HashSet<Endpoint<?>>(){{add(endpoint);}}).get();
int[] gens = meta.getEndpoint(endpoint);

latest = gens[0];
Expand Down
53 changes: 31 additions & 22 deletions src/main/java/org/quiltmc/installer/LaunchJson.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ public static CompletableFuture<String> getMmcJson(VersionManifest.Version gameV
Map<String,Map<String, String>> downloads = (Map<String, Map<String, String>>) vanillaMap.get("downloads");
Map<String, String> client = downloads.get("client");

Map<String, Object> mainJar = Map.of(
"downloads", Map.of("artifact",client),
"name",clientName
);
Map<String, Object> mainJar = new HashMap<String, Object>() {{
put("downloads", new HashMap<String, Object>() {{
put("artifact", client);
}});
put("name", clientName);
}};

// remove lwjgl as it is handled separately by the pack generator
List<Map<String, String>> vanillaLibraries = (List<Map<String, String>>) vanillaMap.get("libraries");
Expand Down Expand Up @@ -111,7 +113,7 @@ private static Map<String, Object> buildPackJsonMap(
}

moddedJsonMap.put("assetIndex",vanilaMap.get("assetIndex"));
moddedJsonMap.put("compatibleJavaMajors", List.of(8, 17, 21, 25));
moddedJsonMap.put("compatibleJavaMajors", Arrays.asList(8, 17, 21, 25));
moddedJsonMap.put("compatibleJavaName", "java-runtime-epsilon");
moddedJsonMap.put("formatVersion", 1);
moddedJsonMap.put("libraries", modifiedLibraries);
Expand All @@ -120,12 +122,12 @@ private static Map<String, Object> buildPackJsonMap(
moddedJsonMap.put("minecraftArguments", minecraftArguments);
moddedJsonMap.put("name", "Minecraft");
moddedJsonMap.put("releaseTime", vanilaMap.get("releaseTime"));
moddedJsonMap.put("requires",List.of(
Map.of(
"suggests", "${lwjgl_version}",
"uid", "${lwjgl_uid}"
)
));
moddedJsonMap.put("requires", Collections.singletonList(
new HashMap<String, String>() {{
put("suggests","${lwjgl_version}");
put("uid","${lwjgl_uid}");
}}
));
moddedJsonMap.put("type", vanilaMap.get("type"));
moddedJsonMap.put("uid", "net.minecraft");
moddedJsonMap.put("version", gameVersion);
Expand All @@ -144,7 +146,8 @@ public static CompletableFuture<String> get(VersionManifest.Version gameVersion)
Map<String, Object> map;

try (InputStreamReader input = new InputStreamReader(connection.getInputStream())) {
map = (Map<String, Object>) Gsons.read(JsonReader.json(input));
//noinspection unchecked
map = (Map<String, Object>) Gsons.read(JsonReader.json(input));
}

// add the -vanilla suffix to the vanilla json 'cause
Expand Down Expand Up @@ -199,6 +202,10 @@ public static CompletableFuture<String> get(GameSide side, VersionManifest.Versi
throw new UncheckedIOException(e); // Handled via .exceptionally(...)
}

if (map == null) {
throw new RuntimeException("Read meta json is null?");
}

// we apply the library upgrades only to the Ornithe instance, not the Vanilla instance
OrnitheMeta.Endpoint<List<Map<String, String>>> libraryUpgradesEndpoint = OrnitheMeta.libraryUpgradesEndpoint(intermediaryGen, gameVersion.id());
OrnitheMeta meta = OrnitheMeta.create(OrnitheMeta.ORNITHE_META_URL, Collections.singleton(libraryUpgradesEndpoint)).join();
Expand All @@ -207,16 +214,10 @@ public static CompletableFuture<String> get(GameSide side, VersionManifest.Versi
if (loaderType == LoaderType.QUILT) {
// Prevents a log warning about being unable to reach the active user beacon on stable versions.
switch (loaderVersion) {
case "0.19.2", "0.19.3", "0.19.4" -> {
@SuppressWarnings("unchecked")
Map<String, List<Object>> arguments = (Map<String,List<Object>>)map.get("arguments");
arguments
.computeIfAbsent("jvm", (key) -> new ArrayList<>())
.add("-Dloader.disable_beacon=true");
}
default -> {
// do nothing
}
case "0.19.2":
case "0.19.4":
case "0.19.3":
disableBeacon(map);
}
}

Expand All @@ -235,6 +236,14 @@ public static CompletableFuture<String> get(GameSide side, VersionManifest.Versi
});
}

private static void disableBeacon(Map<?, ?> map) {
@SuppressWarnings("unchecked")
Map<String, List<Object>> arguments = (Map<String,List<Object>>)map.get("arguments");
arguments
.computeIfAbsent("jvm", (key) -> new ArrayList<>())
.add("-Dloader.disable_beacon=true");
}

private LaunchJson() {
}
}
36 changes: 27 additions & 9 deletions src/main/java/org/quiltmc/installer/MmcPackCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,15 @@
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class MmcPackCreator {
private static final String ENV_WRAPPER_COMMAND = "WrapperCommand=env __GL_THREADED_OPTIMIZATIONS=0";
Expand Down Expand Up @@ -167,9 +170,13 @@ private static String addLibraryUpgrades(Path instanceZipRoot, String gameVersio
String libName = name.substring(name.indexOf(':')+1, name.lastIndexOf(':'));
String version = name.substring(name.lastIndexOf(':')+1);

Files.writeString(instanceZipRoot.resolve("patches").resolve(uid + ".json"),
String.format(patch, name, url, libName, uid, version));
components.add(Map.of("cachedName", libName,"cachedVersion", version,"uid", uid));
Files.write(instanceZipRoot.resolve("patches").resolve(uid + ".json"),
String.format(patch, name, url, libName, uid, version).getBytes(StandardCharsets.UTF_8));
components.add(new HashMap<String, Object>() {{
put("cachedName", libName);
put("cachedVersion", version);
put("uid", uid);
}});
}


Expand Down Expand Up @@ -222,16 +229,27 @@ public static void compileMmcZip(Path outPutDir, String gameVersion, LoaderType
Path zipFile = outPutDir.resolve("Ornithe Gen" + intermediaryGen.orElseGet(IntermediaryGenerations::stable) + " " + loaderType.getLocalizedName() + " " + gameVersion + ".zip");
Files.deleteIfExists(zipFile);

try (FileSystem fs = FileSystems.newFileSystem(zipFile, Map.of("create", "true"))) {
// This is a god awful workaround, because paths can't be cleanly converted to URIs in j8, and for some reason, you can't pass parameters into newFileSystem with a path argument.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they can be converted, it's just

URI.create("jar:" + path.toUri())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That doesn't work on windows, cause:

  • Windows uses \, which is an illegal char.
  • Windows also has the drive name, which itself is illegal to have in a URI.
  • I can't replace \ with / and then urlencode it, because it then encodes /, which then breaks the path.
  • I can't just manually escape space and colon (the two main offenders of breaking path), cause the path component is still somehow undefined.

I love J8 path API on windows :)

Copy link

@wagyourtail wagyourtail Sep 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, path.toUri on windows looks like file:///C:/path/to/file on windows. and is a valid uri
and adding jar: on the front makes FileSystems recognize it as a zip properly on java 8 as the scheme becomes jar:file:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still ends up at the exact same "path component is undefined" error.

// Thanks Java :)
ZipOutputStream dummyZipOutputStream = new ZipOutputStream(Files.newOutputStream(zipFile.toFile().toPath()));
// I need to put an entry inside, or it creates a 0-byte file, which filesystem doesn't like
dummyZipOutputStream.putNextEntry(new ZipEntry("mmc-pack.json"));
dummyZipOutputStream.write("if you see this, this didn't work".getBytes(StandardCharsets.UTF_8));
dummyZipOutputStream.closeEntry();
dummyZipOutputStream.close();
// End god awful workaround

// And now we load that dummy zip as a filesystem and actually make it real.
try (FileSystem fs = FileSystems.newFileSystem(zipFile, (ClassLoader) null)) {
Files.copy(MmcPackCreator.class.getResourceAsStream(examplePackDir + "/" + iconPath), fs.getPath(iconPath));
Files.writeString(fs.getPath(instanceCfgPath), transformedInstanceCfg);
Files.write(fs.getPath(instanceCfgPath), transformedInstanceCfg.getBytes(StandardCharsets.UTF_8));
Files.createDirectory(fs.getPath("patches"));
Files.writeString(fs.getPath(intermediaryJsonPath), transformedIntermediaryJson);
Files.writeString(fs.getPath(minecraftPatchPath), transformedMinecraftJson);
Files.write(fs.getPath(intermediaryJsonPath), transformedIntermediaryJson.getBytes(StandardCharsets.UTF_8));
Files.write(fs.getPath(minecraftPatchPath), transformedMinecraftJson.getBytes(StandardCharsets.UTF_8));
String packJsonWithLibraries = addLibraryUpgrades(fs.getPath("/"), gameVersion,
loaderType, loaderVersion, intermediaryGen, intermediary, transformedPackJson);

Files.writeString(fs.getPath(packJsonPath), packJsonWithLibraries);
Files.write(fs.getPath(packJsonPath), packJsonWithLibraries.getBytes(StandardCharsets.UTF_8));
}

if (copyProfilePath) {
Expand All @@ -250,7 +268,7 @@ private static String readResource(String dir, String path) throws IOException {
for (int length; (length = resource.read(buffer)) != -1; ) {
os.write(buffer, 0, length);
}
return os.toString(StandardCharsets.UTF_8);
return os.toString(StandardCharsets.UTF_8.name());
}

static {
Expand Down
26 changes: 14 additions & 12 deletions src/main/java/org/quiltmc/installer/OrnitheMeta.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,20 @@ public static Endpoint<int[]> intermediaryGenerationsEndpoint() {
continue;
}
switch (reader.nextName()) {
case "latestIntermediaryGeneration" -> {
case "latestIntermediaryGeneration":
if (reader.peek() != JsonToken.NUMBER) {
throw new ParseException("Version must be a number", reader);
}
gens[0] = reader.nextInt();
}
case "stableIntermediaryGeneration" -> {
break;
case "stableIntermediaryGeneration":
if (reader.peek() != JsonToken.NUMBER) {
throw new ParseException("maven must be a number", reader);
}
gens[1] = reader.nextInt();
}
default -> reader.skipValue();
break;
default:
reader.skipValue();
}
}

Expand Down Expand Up @@ -125,19 +126,20 @@ public static final Endpoint<List<Intermediary>> intermediaryVersionsEndpoint(Op
continue;
}
switch (reader.nextName()) {
case "version" -> {
case "version":
if (reader.peek() != JsonToken.STRING) {
throw new ParseException("Version must be a string", reader);
}
version = reader.nextString();
}
case "maven" -> {
break;
case "maven":
if (reader.peek() != JsonToken.STRING) {
throw new ParseException("maven must be a string", reader);
}
maven = reader.nextString();
}
case "stable" -> reader.nextBoolean(); // TODO
break;
case "stable":
reader.nextBoolean(); // TODO
}
}

Expand All @@ -161,7 +163,7 @@ public static final Endpoint<List<Intermediary>> intermediaryVersionsEndpoint(Op
}

public static String launchJsonEndpointPath(GameSide side, LoaderType loaderType, String loaderVersion, OptionalInt intermediaryGen, Intermediary intermediary) {
return "/v3/versions" + (intermediaryGen.isEmpty() ? "" : ("/gen" + intermediaryGen.getAsInt())) + String.format(side.launchJsonEndpoint(), loaderType.getName(), intermediary.getVersion(), loaderVersion);
return "/v3/versions" + (!intermediaryGen.isPresent() ? "" : ("/gen" + intermediaryGen.getAsInt())) + String.format(side.launchJsonEndpoint(), loaderType.getName(), intermediary.getVersion(), loaderVersion);
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -275,7 +277,7 @@ public static final class Endpoint<T> {
private final ThrowingFunction<JsonReader, T, ParseException> deserializer;

Endpoint(OptionalInt intermediaryGen, String endpointPath, ThrowingFunction<JsonReader, T, ParseException> deserializer) {
this((intermediaryGen.isEmpty() ? "" : ("/gen" + intermediaryGen.getAsInt())) + endpointPath, deserializer);
this((!intermediaryGen.isPresent() ? "" : ("/gen" + intermediaryGen.getAsInt())) + endpointPath, deserializer);
}

Endpoint(String endpointPath, ThrowingFunction<JsonReader, T, ParseException> deserializer) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/quiltmc/installer/VersionManifest.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public final class VersionManifest implements Collection<VersionManifest.Version
public static CompletableFuture<VersionManifest> create(OptionalInt intermediaryGen) {
return CompletableFuture.supplyAsync(() -> {
try {
URL url = new URL(intermediaryGen.isEmpty()
URL url = new URL(!intermediaryGen.isPresent()
? LAUNCHER_META_URL
: String.format(LAUNCHER_META_BY_GEN_URL, intermediaryGen.getAsInt()));
URLConnection connection = Connections.openConnection(url);
Expand Down
Loading