Skip to content

Commit 71dd78c

Browse files
committed
feat: Add mod id support to the deploader
1 parent c472733 commit 71dd78c

File tree

4 files changed

+179
-23
lines changed

4 files changed

+179
-23
lines changed

build.gradle.kts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ plugins {
44

55
group = "com.falsepattern"
66

7+
//bump this after ANY change to the deploader!
8+
val deploaderVersion = 2
9+
710
minecraft_fp {
811
java {
912
compatibility = jvmDowngrader
@@ -95,7 +98,7 @@ val depLoaderJar = tasks.register<Jar>(depLoader.jarTaskName) {
9598
archiveVersion = minecraft_fp.mod.version
9699
archiveClassifier = "deploader"
97100
manifest {
98-
attributes("FPLib-Deploader-Version" to "1")
101+
attributes("FPLib-Deploader-Version" to deploaderVersion)
99102
}
100103
}
101104

src/deploader/java/com/falsepattern/deploader/DepRoot.java

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,21 @@
2222

2323
package com.falsepattern.deploader;
2424

25+
import com.google.gson.Gson;
26+
import com.google.gson.JsonElement;
27+
import com.google.gson.TypeAdapter;
28+
import com.google.gson.TypeAdapterFactory;
2529
import com.google.gson.annotations.Expose;
30+
import com.google.gson.reflect.TypeToken;
31+
import com.google.gson.stream.JsonReader;
32+
import com.google.gson.stream.JsonWriter;
2633
import lombok.Data;
34+
import lombok.RequiredArgsConstructor;
2735
import lombok.experimental.Accessors;
36+
import lombok.val;
37+
import org.jetbrains.annotations.Nullable;
2838

39+
import java.io.IOException;
2940
import java.util.List;
3041

3142
@Data
@@ -37,7 +48,7 @@ public class DepRoot {
3748
@Expose
3849
private Integer maxJava;
3950
@Expose
40-
private List<String> bundledArtifacts;
51+
private List<Dependency> bundledArtifacts;
4152
@Expose
4253
private List<String> repositories;
4354
@Expose
@@ -60,10 +71,75 @@ public static class Dependencies {
6071
@Accessors(fluent = true)
6172
public static class SidedDependencies {
6273
@Expose
63-
private List<String> common;
74+
private List<Dependency> common;
6475
@Expose
65-
private List<String> client;
76+
private List<Dependency> client;
6677
@Expose
67-
private List<String> server;
78+
private List<Dependency> server;
79+
}
80+
81+
@Data
82+
@Accessors(fluent = true)
83+
public static class Dependency {
84+
@Expose
85+
private @Nullable String modid;
86+
@Expose
87+
private String artifact;
88+
89+
@RequiredArgsConstructor
90+
public static class Adapter extends TypeAdapter<Dependency> {
91+
private final TypeAdapter<JsonElement> jsonElementTypeAdapter;
92+
93+
@Override
94+
public void write(JsonWriter out, Dependency value) throws IOException {
95+
if (value.modid() == null) {
96+
out.value(value.artifact());
97+
return;
98+
}
99+
out.beginObject();
100+
out.name("modid");
101+
out.value(value.modid());
102+
out.name("artifact");
103+
out.value(value.artifact());
104+
out.endObject();
105+
}
106+
107+
@Override
108+
public Dependency read(JsonReader in) throws IOException {
109+
val dep = new Dependency();
110+
switch (in.peek()) {
111+
case STRING: {
112+
val artifact = in.nextString();
113+
dep.artifact(artifact);
114+
break;
115+
}
116+
case BEGIN_OBJECT: {
117+
val object = jsonElementTypeAdapter.read(in).getAsJsonObject();
118+
if (!object.has("artifact")) {
119+
throw new IllegalArgumentException("Missing artifact in dependency object!");
120+
}
121+
dep.artifact(object.get("artifact").getAsString());
122+
if (object.has("modid")) {
123+
dep.modid(object.get("modid").getAsString());
124+
}
125+
break;
126+
}
127+
}
128+
return dep;
129+
}
130+
131+
public static class Factory implements TypeAdapterFactory {
132+
@SuppressWarnings("unchecked")
133+
@Override
134+
public <T> @Nullable TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
135+
if (!Dependency.class.isAssignableFrom(type.getRawType())) {
136+
return null;
137+
}
138+
val jsonElementAdapter = gson.getAdapter(JsonElement.class);
139+
140+
return (TypeAdapter<T>) new Adapter(jsonElementAdapter);
141+
}
142+
}
143+
}
68144
}
69145
}

src/deploader/java/com/falsepattern/deploader/DependencyLoaderImpl.java

Lines changed: 86 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@
3939
import org.jetbrains.annotations.NotNull;
4040
import org.jetbrains.annotations.Nullable;
4141

42+
import cpw.mods.fml.common.MetadataCollection;
43+
import cpw.mods.fml.common.ModMetadata;
44+
4245
import javax.swing.JFrame;
4346
import javax.swing.JLabel;
4447
import javax.swing.JOptionPane;
@@ -53,6 +56,7 @@
5356
import java.io.IOException;
5457
import java.io.InputStream;
5558
import java.io.InputStreamReader;
59+
import java.lang.reflect.Field;
5660
import java.net.MalformedURLException;
5761
import java.net.URISyntaxException;
5862
import java.net.URL;
@@ -92,6 +96,8 @@ public class DependencyLoaderImpl {
9296
private static final Set<Path> alreadyScannedSources = new ConcurrentSet<>();
9397
private static final Map<String, Version> loadedLibraries = new ConcurrentHashMap<>();
9498
private static final Map<String, String> loadedLibraryMods = new ConcurrentHashMap<>();
99+
private static final Map<String, Version> loadedModIds = new ConcurrentHashMap<>();
100+
private static final Map<String, String> loadedModIdMods = new ConcurrentHashMap<>();
95101
private static final Set<String> remoteMavenRepositories = new ConcurrentSet<>();
96102
private static final Set<String> localMavenRepositories = new ConcurrentSet<>();
97103
static final Logger LOG = LogManager.getLogger("FalsePatternLib DepLoader");
@@ -106,6 +112,16 @@ public class DependencyLoaderImpl {
106112
private static final Path libDir;
107113
private static final Path modsDir;
108114
private static final Path tempDir;
115+
private static final Field metadataCollectionModListAccessor;
116+
117+
static {
118+
try {
119+
metadataCollectionModListAccessor = MetadataCollection.class.getDeclaredField("modList");
120+
} catch (NoSuchFieldException e) {
121+
throw new RuntimeException(e);
122+
}
123+
metadataCollectionModListAccessor.setAccessible(true);
124+
}
109125

110126
private static AtomicBoolean modDownloaded = new AtomicBoolean(false);
111127

@@ -260,7 +276,8 @@ public static CompletableFuture<Void> loadLibrariesAsync(Library... libraries) {
260276
library.preferredVersion,
261277
library.regularSuffix,
262278
library.devSuffix,
263-
false);
279+
false,
280+
null);
264281
futures.add(CompletableFuture.supplyAsync(task::load, executor));
265282
}
266283
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenAccept(ignored -> {
@@ -274,6 +291,26 @@ public static CompletableFuture<Void> loadLibrariesAsync(Library... libraries) {
274291
});
275292
}
276293

294+
@SneakyThrows
295+
private static void readMCMod(InputStream input, String name) {
296+
val meta = MetadataCollection.from(input, name);
297+
val modList = (ModMetadata[])metadataCollectionModListAccessor.get(meta);
298+
for (val mod: modList) {
299+
val id = mod.modId;
300+
if (id != null) {
301+
val versionStr = mod.version;
302+
final Version version;
303+
if (versionStr != null) {
304+
version = Version.parse(versionStr);
305+
} else {
306+
version = new RawVersion("unknown");
307+
}
308+
loadedModIds.put(id, version);
309+
loadedModIdMods.put(id, name);
310+
}
311+
}
312+
}
313+
277314
private static boolean scanForDepSpecs(URL source, List<URL> output, List<URL> jijURLs) {
278315
if (!source.getProtocol().equals("file")) {
279316
return false;
@@ -298,6 +335,9 @@ private static boolean scanForDepSpecs(URL source, List<URL> output, List<URL> j
298335
ZipEntry entry;
299336
while ((entry = jarFile.getNextEntry()) != null) {
300337
val name = entry.getName();
338+
if (name.equals("mcmod.info")) {
339+
readMCMod(jarFile, source.toString());
340+
}
301341
if (!name.startsWith("META-INF/"))
302342
continue;
303343
if (name.endsWith(".json") && name.matches("META-INF/\\w+.json")) {
@@ -430,7 +470,12 @@ public static void executeDependencyLoading() {
430470
JOptionPane.showMessageDialog(null, "A minecraft mod has been downloaded by the FalsePatternLib dependency downloader.\nYou must restart the game to apply these changes.", "Mod Dependency Download notice", JOptionPane.WARNING_MESSAGE);
431471
} catch (Exception ignored) {}
432472
}
433-
throw new ModDependencyDownloaded("A minecraft mod has been downloaded by the FalsePatternLib dependency downloader, and requires a game restart to get installed properly.");
473+
val msg = "A minecraft mod has been downloaded by the FalsePatternLib dependency downloader, and requires a game restart to get installed properly.";
474+
for (int i = 0; i < 16; i++) {
475+
LOG.warn(msg);
476+
}
477+
System.exit(0);
478+
throw new ModDependencyDownloaded(msg);
434479
}
435480
}
436481

@@ -495,6 +540,7 @@ public ModDependencyDownloaded(String message) {
495540
}
496541
val builder = new GsonBuilder();
497542
builder.excludeFieldsWithoutExposeAnnotation();
543+
builder.registerTypeAdapterFactory(new DepRoot.Dependency.Adapter.Factory());
498544
val gson = builder.create();
499545
json.remove("identifier");
500546
val root = gson.fromJson(json, DepRoot.class);
@@ -524,8 +570,8 @@ public ModDependencyDownloaded(String message) {
524570
if (bundled == null) {
525571
continue;
526572
}
527-
for (String artifact : bundled) {
528-
val parts = artifact.split(":");
573+
for (var dep : bundled) {
574+
val parts = dep.artifact().split(":");
529575
if (parts.length < 3) {
530576
LOG.error("Invalid bundled artifact: {}", dependencySpec);
531577
continue;
@@ -549,11 +595,22 @@ public ModDependencyDownloaded(String message) {
549595
dependencySpec.source());
550596
}
551597
val id = groupId + ":" + artifactId + ":" + classifier;
598+
val src = dependencySpec.source();
552599
if (!loadedLibraries.containsKey(id)) {
553600
loadedLibraries.put(id, version);
554601
}
555602
if (!loadedLibraryMods.containsKey(id)) {
556-
loadedLibraryMods.put(id, dependencySpec.source());
603+
loadedLibraryMods.put(id, src);
604+
}
605+
val modid = dep.modid();
606+
if (modid != null) {
607+
LOG.info("With modid: {}", modid);
608+
if (!loadedModIds.containsKey(modid)) {
609+
loadedModIds.put(modid, version);
610+
}
611+
if (!loadedModIdMods.containsKey(modid)) {
612+
loadedModIdMods.put(modid, src);
613+
}
557614
}
558615
}
559616
}
@@ -578,7 +635,7 @@ public ModDependencyDownloaded(String message) {
578635
val source = scopedSidedDep.source;
579636
val scope = scopedSidedDep.scope;
580637
val dep = scopedSidedDep.dep;
581-
val parts = dep.split(":");
638+
val parts = dep.artifact().split(":");
582639
if (parts.length < 3) {
583640
LOG.error("Invalid dependency: {}", dep);
584641
return null;
@@ -610,7 +667,8 @@ public ModDependencyDownloaded(String message) {
610667
version,
611668
classifier,
612669
classifier,
613-
scopedSidedDep.mod));
670+
scopedSidedDep.mod,
671+
dep.modid()));
614672
})
615673
.filter(Objects::nonNull)
616674
.collect(Collectors.toSet());
@@ -620,7 +678,7 @@ public ModDependencyDownloaded(String message) {
620678
return artifacts;
621679
}
622680

623-
private static Stream<ScopedSidedDep> concat(ScopedDep it, @Nullable Stream<ScopedSidedDep> prev, List<String> deps, DependencySide side) {
681+
private static Stream<ScopedSidedDep> concat(ScopedDep it, @Nullable Stream<ScopedSidedDep> prev, List<DepRoot.Dependency> deps, DependencySide side) {
624682
if (deps != null) {
625683
val newStream = deps.stream().map(dep -> new ScopedSidedDep(it.source, it.mod, new ScopeSide(it.scope, side), dep));
626684
if (prev == null) {
@@ -826,7 +884,7 @@ private static class ScopedSidedDep {
826884
public final String source;
827885
public final boolean mod;
828886
public final ScopeSide scope;
829-
public final String dep;
887+
public final DepRoot.Dependency dep;
830888
}
831889

832890
@RequiredArgsConstructor
@@ -851,6 +909,7 @@ private static class DependencyLoadTask {
851909
private final String regularSuffix;
852910
private final String devSuffix;
853911
private final boolean isMod;
912+
private final String modId;
854913

855914
private String suffix;
856915
private String artifactLogName;
@@ -865,7 +924,11 @@ private static class DependencyLoadTask {
865924
private @Nullable URL load() {
866925
setupLibraryNames();
867926
if (loadedLibraries.containsKey(artifact)) {
868-
alreadyLoaded();
927+
alreadyLoaded(false);
928+
return null;
929+
}
930+
if (isMod && loadedModIds.containsKey(modId)) {
931+
alreadyLoaded(true);
869932
return null;
870933
}
871934
setupPaths();
@@ -909,14 +972,14 @@ private void setupLibraryNames() {
909972
artifact = groupId + ":" + artifactId + ":" + suffix;
910973
}
911974

912-
private void alreadyLoaded() {
913-
val currentVer = loadedLibraries.get(artifact);
975+
private void alreadyLoaded(boolean fromModId) {
976+
val currentVer = fromModId ? loadedModIds.get(modId) : loadedLibraries.get(artifact);
914977
if (currentVer.equals(preferredVersion)) {
915978
return;
916979
}
917980
val rangeString = "(minimum: " + minVersion + (maxVersion == null ? "" : ", maximum: " + maxVersion) + ")";
918981
if (minVersion.compareTo(currentVer) > 0 || (maxVersion != null && maxVersion.compareTo(currentVer) < 0)) {
919-
for (int i = 0; i < 16; i++) {
982+
for (int i = 0; i < 4; i++) {
920983
LOG.fatal("ALERT VVVVVVVVVVVV ALERT");
921984
}
922985
LOG.fatal("Library {}:{}{} already loaded with version {}, "
@@ -928,8 +991,8 @@ private void alreadyLoaded() {
928991
currentVer,
929992
rangeString,
930993
loadingModId,
931-
loadedLibraryMods.get(artifact));
932-
for (int i = 0; i < 16; i++) {
994+
fromModId ? loadedModIdMods.get(modId) : loadedLibraryMods.get(artifact));
995+
for (int i = 0; i < 4; i++) {
933996
LOG.fatal("ALERT ^^^^^^^^^^^^ ALERT");
934997
}
935998
} else {
@@ -944,7 +1007,7 @@ private void alreadyLoaded() {
9441007
currentVer,
9451008
rangeString,
9461009
loadingModId,
947-
loadedLibraryMods.get(artifact));
1010+
fromModId ? loadedModIdMods.get(modId) : loadedLibraryMods.get(artifact));
9481011
}
9491012
}
9501013

@@ -978,6 +1041,9 @@ private void setupPaths() {
9781041
addToClasspath(theUrl);
9791042
}
9801043
loadedLibraries.put(artifact, preferredVersion);
1044+
if (isMod && modId != null) {
1045+
loadedModIds.put(modId, preferredVersion);
1046+
}
9811047
LOG.debug("Library {} successfully loaded from disk!", artifactLogName);
9821048
return theUrl;
9831049
} catch (Exception e) {
@@ -1075,6 +1141,10 @@ private void validateDownloadsAllowed() {
10751141
if (!isMod) {
10761142
addToClasspath(diskUrl);
10771143
}
1144+
if (isMod && modId != null) {
1145+
loadedModIds.put(modId, preferredVersion);
1146+
loadedModIdMods.put(modId, loadingModId);
1147+
}
10781148
return diskUrl;
10791149
}
10801150
}

0 commit comments

Comments
 (0)