Skip to content

Commit a35bb81

Browse files
committed
Rework SpongeForge mod locators and load resources in dev
1 parent 6ad9559 commit a35bb81

File tree

11 files changed

+192
-68
lines changed

11 files changed

+192
-68
lines changed

bootstrap-dev/src/main/java/org/spongepowered/bootstrap/dev/SpongeDevClasspathFixer.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,26 +161,26 @@ public boolean process(final List<Path[]> classpath) {
161161
});
162162
}
163163

164-
final StringBuilder gameResourcesEnvBuilder = new StringBuilder();
164+
final StringBuilder resourcesEnvBuilder = new StringBuilder();
165165
for (final Path resource : gameLibs) {
166-
gameResourcesEnvBuilder.append(resource).append(';');
166+
resourcesEnvBuilder.append(resource).append(File.pathSeparator);
167167
}
168168
for (final List<Path> project : unknownProjects.values()) {
169169
for (final Path resource : project) {
170-
gameResourcesEnvBuilder.append(resource).append('&');
170+
resourcesEnvBuilder.append(resource).append('&');
171171
}
172-
gameResourcesEnvBuilder.setCharAt(gameResourcesEnvBuilder.length() - 1, ';');
172+
resourcesEnvBuilder.setCharAt(resourcesEnvBuilder.length() - 1, File.pathSeparatorChar);
173173
}
174174
for (final Path resource : spongeImplUnion) {
175-
gameResourcesEnvBuilder.append(resource).append('&');
175+
resourcesEnvBuilder.append(resource).append('&');
176176
}
177-
gameResourcesEnvBuilder.setLength(gameResourcesEnvBuilder.length() - 1);
178-
final String gameResourcesEnv = gameResourcesEnvBuilder.toString();
177+
resourcesEnvBuilder.setLength(resourcesEnvBuilder.length() - 1);
178+
final String resourcesEnv = resourcesEnvBuilder.toString();
179179

180180
if (DEBUG) {
181-
System.out.println("Game resources env: " + gameResourcesEnv);
181+
System.out.println("Resources env: " + resourcesEnv);
182182
}
183-
System.setProperty("sponge.gameResources", gameResourcesEnv);
183+
System.setProperty("sponge.resources", resourcesEnv);
184184
return true;
185185
}
186186
}

forge/build.gradle.kts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,9 @@ extensions.configure(UserDevExtension::class) {
223223
environment("MOD_CLASSES", "nop")
224224
}
225225

226-
create("client") {
227-
workingDirectory(file("run/client"))
228-
}
226+
create("client")
229227

230228
create("server") {
231-
workingDirectory(file("run/client"))
232229
args("--nogui")
233230
}
234231
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* This file is part of Sponge, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) SpongePowered <https://www.spongepowered.org>
5+
* Copyright (c) contributors
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
package org.spongepowered.forge.applaunch.loading.moddiscovery;
26+
27+
import cpw.mods.jarhandling.SecureJar;
28+
import net.minecraftforge.forgespi.locating.IModFile;
29+
import net.minecraftforge.forgespi.locating.IModProvider;
30+
import org.apache.logging.log4j.LogManager;
31+
import org.apache.logging.log4j.Logger;
32+
33+
import java.io.IOException;
34+
import java.nio.file.Files;
35+
import java.nio.file.Path;
36+
import java.util.Map;
37+
import java.util.concurrent.atomic.AtomicReference;
38+
import java.util.function.Consumer;
39+
import java.util.stream.Stream;
40+
41+
public abstract class AbstractModProvider implements IModProvider {
42+
private static final Logger LOGGER = LogManager.getLogger();
43+
44+
@Override
45+
public boolean isValid(final IModFile modFile) {
46+
return true;
47+
}
48+
49+
@Override
50+
public void initArguments(final Map<String, ?> arguments) {
51+
}
52+
53+
@Override
54+
public void scanFile(final IModFile file, final Consumer<Path> pathConsumer) {
55+
LOGGER.debug("Scan started: {}", file);
56+
final SecureJar jar = file.getSecureJar();
57+
58+
Consumer<Path> consumer = pathConsumer;
59+
final AtomicReference<SecureJar.Status> minStatus = new AtomicReference<>(SecureJar.Status.NONE);
60+
if (jar.hasSecurityData()) {
61+
minStatus.set(SecureJar.Status.VERIFIED);
62+
consumer = path -> {
63+
pathConsumer.accept(path);
64+
SecureJar.Status status = jar.verifyPath(path);
65+
if (status.ordinal() < minStatus.get().ordinal())
66+
minStatus.set(status);
67+
};
68+
}
69+
70+
try (final Stream<Path> files = Files.walk(jar.getRootPath())) {
71+
files.filter(p -> p.toString().endsWith(".class")).forEach(consumer);
72+
} catch (IOException e) {
73+
LOGGER.debug("Scan failed: {}", file);
74+
minStatus.set(SecureJar.Status.NONE);
75+
}
76+
77+
file.setSecurityStatus(minStatus.get());
78+
LOGGER.debug("Scan finished: {}", file);
79+
}
80+
}

forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/PluginFileParser.java

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,16 @@
2424
*/
2525
package org.spongepowered.forge.applaunch.loading.moddiscovery;
2626

27+
import cpw.mods.jarhandling.JarMetadata;
2728
import cpw.mods.jarhandling.SecureJar;
29+
import net.minecraftforge.fml.loading.moddiscovery.AbstractModProvider;
2830
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
2931
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
32+
import net.minecraftforge.fml.loading.moddiscovery.ModFileParser;
3033
import net.minecraftforge.fml.loading.moddiscovery.ModJarMetadata;
3134
import net.minecraftforge.forgespi.language.IModFileInfo;
3235
import net.minecraftforge.forgespi.locating.IModFile;
33-
import net.minecraftforge.forgespi.locating.IModLocator;
34-
import net.minecraftforge.forgespi.locating.ModFileFactory;
36+
import net.minecraftforge.forgespi.locating.IModProvider;
3537
import org.spongepowered.common.applaunch.AppLaunch;
3638
import org.spongepowered.common.applaunch.metadata.PluginMetadataFixer;
3739
import org.spongepowered.common.applaunch.plugin.PluginPlatformConstants;
@@ -46,7 +48,11 @@
4648
import java.nio.file.Path;
4749
import java.util.List;
4850

51+
@SuppressWarnings("UnstableApiUsage")
4952
public final class PluginFileParser {
53+
private static final String MODS_TOML = "META-INF/mods.toml";
54+
private static final String MODULE_INFO = "module-info.class";
55+
5056
private static Constructor<ModJarMetadata> modJarMetadataConstructor;
5157

5258
static {
@@ -58,7 +64,7 @@ public final class PluginFileParser {
5864
}
5965
}
6066

61-
private static IModFileInfo parsePluginMetadata(final IModFile iModFile) {
67+
private static IModFileInfo parsePluginFileInfo(final IModFile iModFile) {
6268
final ModFile modFile = (ModFile) iModFile;
6369
AppLaunch.logger().debug("Considering plugin file candidate {}", modFile.getFilePath());
6470

@@ -82,6 +88,14 @@ private static IModFileInfo parsePluginMetadata(final IModFile iModFile) {
8288
}
8389
}
8490

91+
private static IModFileInfo parseModFileInfo(final IModFile iModFile) {
92+
return ModFileParser.modsTomlParser(iModFile);
93+
}
94+
95+
private static IModFileInfo parseLibraryFileInfo(final IModFile iModFile) {
96+
return DummyModProvider.INSTANCE.manifestParser(iModFile);
97+
}
98+
8599
private static ModJarMetadata newModJarMetadata() {
86100
try {
87101
return modJarMetadataConstructor.newInstance();
@@ -90,13 +104,56 @@ private static ModJarMetadata newModJarMetadata() {
90104
}
91105
}
92106

93-
public static ModFile newPluginInstance(final IModLocator locator, final Path... path) {
94-
ModJarMetadata mjm = newModJarMetadata();
95-
ModFile modFile = (ModFile) ModFileFactory.FACTORY.build(SecureJar.from(jar -> mjm, path), locator, PluginFileParser::parsePluginMetadata);
96-
mjm.setModFile(modFile);
97-
return modFile;
107+
private static boolean useModJarMetadata(final SecureJar jar) {
108+
final SecureJar.ModuleDataProvider data = jar.moduleDataProvider();
109+
if (data.findFile(PluginFileParser.MODULE_INFO).isPresent()) {
110+
return false;
111+
}
112+
return data.findFile(PluginFileParser.MODS_TOML).isPresent() || data.findFile(PluginPlatformConstants.METADATA_FILE_LOCATION).isPresent();
113+
}
114+
115+
public static ModFile newModFile(final IModProvider provider, boolean allowUnknown, final Path... paths) {
116+
final ModJarMetadata mjm = newModJarMetadata();
117+
final SecureJar jar = SecureJar.from(j -> useModJarMetadata(j) ? mjm : JarMetadata.from(j, paths), paths);
118+
119+
final SecureJar.ModuleDataProvider data = jar.moduleDataProvider();
120+
final String type = data.getManifest().getMainAttributes().getValue("FMLModType");
121+
122+
if (data.findFile(PluginFileParser.MODS_TOML).isPresent()) {
123+
ModFile modFile = new ModFile(jar, provider, PluginFileParser::parseModFileInfo, type == null ? "MOD" : type);
124+
mjm.setModFile(modFile);
125+
return modFile;
126+
}
127+
128+
if (data.findFile(PluginPlatformConstants.METADATA_FILE_LOCATION).isPresent()) {
129+
ModFile modFile = new ModFile(jar, provider, PluginFileParser::parsePluginFileInfo, type == null ? "MOD" : type);
130+
mjm.setModFile(modFile);
131+
return modFile;
132+
}
133+
134+
if (!allowUnknown && type == null) {
135+
throw new IllegalArgumentException("Unknown mod file type");
136+
}
137+
138+
return new ModFile(jar, provider, PluginFileParser::parseLibraryFileInfo, type == null ? "GAMELIBRARY" : type);
139+
}
140+
141+
public static ModFile newLibraryFile(final IModProvider provider, final Path... paths) {
142+
final SecureJar jar = SecureJar.from(paths);
143+
return new ModFile(jar, provider, PluginFileParser::parseLibraryFileInfo, "GAMELIBRARY");
98144
}
99145

100-
private PluginFileParser() {
146+
private static class DummyModProvider extends AbstractModProvider {
147+
private static final DummyModProvider INSTANCE = new DummyModProvider();
148+
149+
@Override
150+
public String name() {
151+
return "dummy";
152+
}
153+
154+
@Override
155+
public IModFileInfo manifestParser(IModFile mod) {
156+
return super.manifestParser(mod);
157+
}
101158
}
102159
}

forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/SpongeForgeDependencyLocator.java

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,8 @@
2727
import cpw.mods.modlauncher.Environment;
2828
import cpw.mods.modlauncher.Launcher;
2929
import net.minecraftforge.fml.loading.FMLEnvironment;
30-
import net.minecraftforge.fml.loading.moddiscovery.AbstractModProvider;
3130
import net.minecraftforge.forgespi.locating.IDependencyLocator;
3231
import net.minecraftforge.forgespi.locating.IModFile;
33-
import net.minecraftforge.forgespi.locating.IModLocator;
3432
import org.apache.logging.log4j.LogManager;
3533
import org.apache.logging.log4j.Logger;
3634
import org.spongepowered.forge.applaunch.loading.moddiscovery.library.Log4JLogger;
@@ -42,14 +40,13 @@
4240
import java.util.List;
4341
import java.util.Map;
4442

45-
// works with ForgeProductionBootstrap to make this whole thing go
4643
public class SpongeForgeDependencyLocator extends AbstractModProvider implements IDependencyLocator {
4744
private static final Logger LOGGER = LogManager.getLogger();
4845

4946
private LibraryManager libraryManager;
5047

5148
@Override
52-
public List<IModFile> scanMods(Iterable<IModFile> loadedMods) {
49+
public List<IModFile> scanMods(final Iterable<IModFile> loadedMods) {
5350
final List<IModFile> modFiles = new ArrayList<>();
5451

5552
// Add Sponge-specific libraries
@@ -64,23 +61,13 @@ public List<IModFile> scanMods(Iterable<IModFile> loadedMods) {
6461
for (final LibraryManager.Library library : this.libraryManager.getAll("main")) {
6562
final Path path = library.file();
6663
SpongeForgeDependencyLocator.LOGGER.debug("Proposing jar {} as a game library", path);
67-
68-
final IModLocator.ModFileOrException fileOrException = createMod(path);
69-
if (fileOrException.ex() != null) {
70-
throw fileOrException.ex();
71-
}
72-
modFiles.add(fileOrException.file());
64+
modFiles.add(PluginFileParser.newLibraryFile(this, path));
7365
}
7466
}
7567

7668
return modFiles;
7769
}
7870

79-
@Override
80-
protected String getDefaultJarModType() {
81-
return IModFile.Type.GAMELIBRARY.name();
82-
}
83-
8471
@Override
8572
public String name() {
8673
return "spongeforge";

forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/SpongeForgeModLocator.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,43 @@
2828
import cpw.mods.modlauncher.Environment;
2929
import cpw.mods.modlauncher.Launcher;
3030
import net.minecraftforge.fml.loading.FMLEnvironment;
31-
import net.minecraftforge.fml.loading.moddiscovery.AbstractModProvider;
3231
import net.minecraftforge.forgespi.locating.IModLocator;
3332
import org.apache.logging.log4j.LogManager;
3433
import org.apache.logging.log4j.Logger;
3534
import org.spongepowered.forge.applaunch.plugin.ForgePluginPlatform;
3635

36+
import java.io.File;
3737
import java.net.URI;
3838
import java.net.URL;
3939
import java.nio.file.FileSystem;
4040
import java.nio.file.FileSystems;
4141
import java.nio.file.Files;
42+
import java.nio.file.Path;
43+
import java.util.ArrayList;
4244
import java.util.List;
4345
import java.util.Locale;
4446
import java.util.Map;
47+
import java.util.stream.Stream;
4548

4649
public final class SpongeForgeModLocator extends AbstractModProvider implements IModLocator {
4750
private static final Logger LOGGER = LogManager.getLogger();
4851

4952
@Override
5053
public List<ModFileOrException> scanMods() {
5154
if (!FMLEnvironment.production) {
52-
return List.of();
55+
final List<ModFileOrException> resources = new ArrayList<>();
56+
final String resourcesProp = System.getProperty("sponge.resources");
57+
if (resourcesProp != null) {
58+
for (final String entry : resourcesProp.split(File.pathSeparator)) {
59+
if (entry.isBlank()) {
60+
continue;
61+
}
62+
63+
final Path[] paths = Stream.of(entry.split("&")).map(Path::of).toArray(Path[]::new);
64+
resources.add(new ModFileOrException(PluginFileParser.newModFile(this, true, paths), null));
65+
}
66+
}
67+
return resources;
5368
}
5469

5570
try {
@@ -66,7 +81,7 @@ public List<ModFileOrException> scanMods() {
6681
} catch (Exception e) {
6782
throw new RuntimeException(e);
6883
}
69-
}).map(this::createMod).toList();
84+
}).map((path -> new ModFileOrException(PluginFileParser.newModFile(this, false, path), null))).toList();
7085
} catch (Exception e) {
7186
LOGGER.error("Failed to scan mod candidates", e);
7287
}

forge/src/applaunch/java/org/spongepowered/forge/applaunch/loading/moddiscovery/locator/EnvironmentPluginLocator.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,14 @@
2424
*/
2525
package org.spongepowered.forge.applaunch.loading.moddiscovery.locator;
2626

27-
import net.minecraftforge.fml.loading.moddiscovery.AbstractModProvider;
2827
import net.minecraftforge.forgespi.locating.IModLocator;
28+
import org.spongepowered.forge.applaunch.loading.moddiscovery.AbstractModProvider;
2929
import org.spongepowered.forge.applaunch.loading.moddiscovery.PluginFileParser;
3030

3131
import java.nio.file.Path;
3232
import java.util.ArrayList;
3333
import java.util.Collections;
3434
import java.util.List;
35-
import java.util.Map;
3635
import java.util.stream.Stream;
3736

3837
public final class EnvironmentPluginLocator extends AbstractModProvider implements IModLocator {
@@ -41,25 +40,16 @@ public final class EnvironmentPluginLocator extends AbstractModProvider implemen
4140
public List<ModFileOrException> scanMods() {
4241
final List<ModFileOrException> modFiles = new ArrayList<>();
4342
for (final Path[] paths : EnvironmentPluginLocator.getPluginsPaths()) {
44-
modFiles.add(new ModFileOrException(PluginFileParser.newPluginInstance(this, paths), null));
43+
modFiles.add(new ModFileOrException(PluginFileParser.newModFile(this, false, paths), null));
4544
}
4645
return modFiles;
4746
}
4847

49-
@Override
50-
protected ModFileOrException createMod(Path path) {
51-
return new ModFileOrException(PluginFileParser.newPluginInstance(this, path), null);
52-
}
53-
5448
@Override
5549
public String name() {
5650
return "environment plugin";
5751
}
5852

59-
@Override
60-
public void initArguments(final Map<String, ?> arguments) {
61-
}
62-
6353
private static List<Path[]> getPluginsPaths() {
6454
final String env = System.getenv("SPONGE_PLUGINS");
6555
if (env == null) {

0 commit comments

Comments
 (0)