Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit 3794f3a

Browse files
authored
More entrypoints! (#198)
* Start on more entrypoints * lowerCamelCase the entrypoint names * Update documentation * Checkstyle * Remove comments because of Loader bug
1 parent ec08e71 commit 3794f3a

File tree

8 files changed

+116
-39
lines changed

8 files changed

+116
-39
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
- uses: eskatos/gradle-command-action@v1
2121
with:
2222
gradle-version: wrapper
23-
arguments: build -x check
23+
arguments: remapAllJars
2424
dependencies-cache-enabled: true
2525
configuration-cache-enabled: false
2626
# Artifact publishing

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Gradle needs a lot of memory to build in parallel.
22
# If you're starved, you can reduce this to 1G and disable parallel building.
3-
org.gradle.jvmargs=-Xmx3G
3+
org.gradle.jvmargs=-Xmx1G
44
org.gradle.parallel=true
55
org.gradle.daemon=false
66
repoName=patchwork-api

patchwork-api-base/src/main/resources/fabric.mod.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
"PatchworkMC"
1414
],
1515
"depends": {
16-
// This is mirrored in the top-level project because of a Loader issue
1716
"fabricloader": ">=0.10.0",
1817
"fabric": ">=0.15.1"
1918
},

patchwork-dispatcher/README.MD

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Patchwork Dispatcher
2+
A sane and simple framework around FML for Patchwork.
3+
4+
This document intends to (eventually) describe how mods are identified and loaded.
5+
## Custom block
6+
Patchwork Patcher will provide the following metadata at the root of the `custom` block:
7+
1. `patchwork:source`: An object with a member named `loader` of value `forge`.
8+
This is for ModMenu, and should not be considered a reliable or stable marker of a patched mod (it will be removed in 1.16)
9+
10+
Additionally, the following metadata will be provided through the `patchwork:patcherMeta` object:
11+
1. `patchedOn`: An [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date that shows when this file was patched.
12+
It should be in UTC time and have the format of the format `yyyy-MM-dd'T'HH:mm'Z'` (which results in something like `2020-10-10T22:03Z`)
13+
2. `patcherVersion`: The version of Patcher that this mod has been patched with.
14+
3. `annotations`: Points to a json file somewhere in the JAR that holds the annotation metadata.
15+
Must either be a valid SemVer version (i.e `1.0.0`), or `develop`. When checking if a Patcher version is recent enough for the current API version, `develop` will always be considered compatible.
16+
4. `parent`: If the mod is a skeleton mod (TODO: Describe in more detail), this tells the mod id of it's parent
17+
5. `children`: If the mod has children, this array lists all additional mod ids that were provided in the original Forge mod.

patchwork-dispatcher/src/main/java/net/patchworkmc/api/ForgeInitializer.java renamed to patchwork-dispatcher/src/main/java/net/patchworkmc/api/ModInstance.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,5 @@
1919

2020
package net.patchworkmc.api;
2121

22-
public interface ForgeInitializer {
23-
String getModId();
24-
25-
void onForgeInitialize();
22+
public interface ModInstance {
2623
}

patchwork-dispatcher/src/main/java/net/patchworkmc/impl/Patchwork.java

Lines changed: 89 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,15 @@
1919

2020
package net.patchworkmc.impl;
2121

22+
import java.util.ArrayList;
2223
import java.util.Collection;
2324
import java.util.HashMap;
2425
import java.util.List;
25-
import java.util.Map;
2626
import java.util.function.Consumer;
2727
import java.util.function.Function;
2828
import java.util.function.Supplier;
2929
import java.util.stream.Collectors;
3030

31-
import org.apache.logging.log4j.LogManager;
32-
import org.apache.logging.log4j.Logger;
3331
import net.minecraftforge.common.MinecraftForge;
3432
import net.minecraftforge.event.RegistryEvent;
3533
import net.minecraftforge.eventbus.api.Event;
@@ -44,12 +42,17 @@
4442
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
4543
import net.minecraftforge.fml.javafmlmod.FMLModContainer;
4644
import net.minecraftforge.registries.ForgeRegistries;
45+
import org.apache.logging.log4j.LogManager;
46+
import org.apache.logging.log4j.Logger;
4747

4848
import net.minecraft.server.dedicated.DedicatedServer;
49+
import net.minecraft.util.Pair;
4950

51+
import net.fabricmc.api.ModInitializer;
5052
import net.fabricmc.loader.api.FabricLoader;
53+
import net.fabricmc.loader.api.metadata.CustomValue;
5154

52-
import net.patchworkmc.api.ForgeInitializer;
55+
import net.patchworkmc.api.ModInstance;
5356
import net.patchworkmc.impl.registries.RegistryEventDispatcher;
5457

5558
public class Patchwork {
@@ -78,29 +81,52 @@ private static void dispatch(Collection<FMLModContainer> mods, Function<ModConta
7881
public static void gatherAndInitializeMods() {
7982
ForgeRegistries.init();
8083

81-
Map<ForgeInitializer, FMLModContainer> mods = new HashMap<>();
82-
84+
List<FMLModContainer> mods = new ArrayList<>();
85+
List<Pair<String, Supplier<ModInstance>>> modInitializers = new ArrayList<>();
8386
// Construct forge mods
8487

85-
List<ForgeInitializer> entrypoints;
88+
// TODO: https://github.com/FabricMC/fabric-loader/pull/313
89+
90+
for (net.fabricmc.loader.api.ModContainer mod : FabricLoader.getInstance().getAllMods()) {
91+
String modId = mod.getMetadata().getId();
8692

87-
try {
88-
entrypoints = FabricLoader.getInstance().getEntrypoints("patchwork", ForgeInitializer.class);
89-
} catch (Throwable t) {
90-
throw new PatchworkInitializationException("Failed to get Patchwork entrypoints!", t);
93+
CustomValue meta = mod.getMetadata().getCustomValue("patchwork:patcher_meta");
94+
95+
if (meta != null && meta.getAsObject().get("parent") != null) {
96+
// synthetic mods are unreliable; don't invoke their entrypoints here
97+
continue;
98+
}
99+
100+
modInitializers.add(new Pair<>(modId, () -> createModInstance(modId)));
101+
102+
if (meta != null) {
103+
CustomValue children = meta.getAsObject().get("children");
104+
105+
if (children != null) {
106+
for (CustomValue customValue : children.getAsArray()) {
107+
String childId = customValue.getAsString();
108+
modInitializers.add(new Pair<>(childId, () -> createModInstance(modId)));
109+
}
110+
}
111+
}
91112
}
92113

93114
PatchworkInitializationException error = null;
94115

95-
for (ForgeInitializer initializer : entrypoints) {
96-
LOGGER.info("Constructing Patchwork mod: " + initializer.getModId());
116+
for (Pair<String, Supplier<ModInstance>> pair : modInitializers) {
117+
String modId = pair.getLeft();
118+
FMLModContainer container = new FMLModContainer(modId);
119+
boolean loaded = false;
97120

98-
FMLModContainer container = new FMLModContainer(initializer.getModId());
99121
ModLoadingContext.get().setActiveContainer(container, new FMLJavaModLoadingContext(container));
100122

101123
try {
102-
// TODO: Supposed to call "container.setMod()" here, but this requires a WIP Patchwork-Patcher feature.
103-
initializer.onForgeInitialize();
124+
ModInstance instance = pair.getRight().get();
125+
126+
if (instance != null) {
127+
container.setMod(instance);
128+
loaded = true;
129+
}
104130
} catch (Throwable t) {
105131
if (error == null) {
106132
error = new PatchworkInitializationException("Failed to construct Patchwork mods");
@@ -127,9 +153,9 @@ public static void gatherAndInitializeMods() {
127153
}
128154

129155
if (unDefinedClass.startsWith("net.minecraft.") || (unDefinedClass.startsWith("net.minecraftforge.") && !unDefinedClass.startsWith("net.minecraftforge.lex."))) {
130-
throw new PatchworkInitializationException("Patchwork mod " + initializer.getModId() + " tried to access an unimplemented " + type + ".", t);
156+
throw new PatchworkInitializationException("Patchwork mod " + modId + " tried to access an unimplemented " + type + ".", t);
131157
} else {
132-
throw new PatchworkInitializationException("Patchwork mod " + initializer.getModId() + " tried to access a missing " + type + " from a missing and undeclared, or outdated dependency.", t);
158+
throw new PatchworkInitializationException("Patchwork mod " + modId + " tried to access a missing " + type + " from a missing and undeclared, or outdated dependency.", t);
133159
}
134160
}
135161

@@ -138,18 +164,24 @@ public static void gatherAndInitializeMods() {
138164

139165
ModLoadingContext.get().setActiveContainer(null, "minecraft");
140166

141-
mods.put(initializer, container);
167+
if (loaded) {
168+
mods.add(container);
169+
}
142170
}
143171

144172
if (error != null) {
145173
throw error;
146174
}
147175

148-
ModList.get().setLoadedMods(mods.values());
176+
ModList.get().setLoadedMods(mods);
177+
// note: forge fires this per-class when it is registered.
178+
dispatchEntrypoint(mods, "patchwork:commonAutomaticSubscribers");
149179
// Send initialization events
180+
dispatch(mods, new RegistryEvent.NewRegistry());
181+
dispatchEntrypoint("patchwork:objectHolders");
182+
dispatchEntrypoint("patchwork:capabilityInject");
150183

151-
dispatch(mods.values(), new RegistryEvent.NewRegistry());
152-
RegistryEventDispatcher.dispatchRegistryEvents(event -> dispatch(mods.values(), event));
184+
RegistryEventDispatcher.dispatchRegistryEvents(event -> dispatch(mods, event));
153185
}
154186

155187
/**
@@ -209,4 +241,39 @@ public static void endOfServerModLoading() {
209241
// Assume there's no error.
210242
MinecraftForge.EVENT_BUS.start();
211243
}
244+
245+
private static ModInstance createModInstance(String modid) {
246+
List<ModInstance> initializer = FabricLoader.getInstance().getEntrypoints("patchwork:modInstance:" + modid, ModInstance.class);
247+
248+
if (initializer.size() > 1) {
249+
throw new AssertionError("Cannot have more than 1 mod_instance for a given modid! aborting!");
250+
} else if (initializer.size() == 1) {
251+
return initializer.get(0);
252+
} else {
253+
return null;
254+
}
255+
}
256+
257+
private static void dispatchEntrypoint(String name) {
258+
FabricLoader.getInstance().getEntrypoints(name, ModInitializer.class).forEach(ModInitializer::onInitialize);
259+
}
260+
261+
private static void dispatchEntrypoint(Collection<FMLModContainer> mods, String name) {
262+
HashMap<String, List<ModInitializer>> map = new HashMap<>();
263+
FabricLoader.getInstance().getEntrypointContainers(name, ModInitializer.class)
264+
.forEach(container -> map.computeIfAbsent(container.getProvider().getMetadata().getId(),
265+
id -> new ArrayList<>())
266+
.add(container.getEntrypoint()));
267+
268+
for (FMLModContainer mod : mods) {
269+
List<ModInitializer> inits = map.get(mod.getModId());
270+
271+
if (inits != null) {
272+
ModLoadingContext.get().setActiveContainer(mod, new FMLJavaModLoadingContext(mod));
273+
inits.forEach(ModInitializer::onInitialize);
274+
}
275+
}
276+
277+
ModLoadingContext.get().setActiveContainer(null, "minecraft");
278+
}
212279
}

patchwork-fml/src/main/java/net/minecraftforge/fml/ModList.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,18 +31,18 @@
3131
import java.util.stream.Collectors;
3232
import java.util.stream.Stream;
3333

34+
import com.google.common.collect.ImmutableList;
3435
import net.minecraftforge.fml.javafmlmod.FMLModContainer;
3536
import net.minecraftforge.fml.loading.moddiscovery.ModFile;
3637
import net.minecraftforge.fml.loading.moddiscovery.ModFileInfo;
3738
import net.minecraftforge.forgespi.language.ModFileScanData;
3839
import org.apache.logging.log4j.LogManager;
3940
import org.apache.logging.log4j.Logger;
40-
import com.google.common.collect.ImmutableList;
4141

4242
import net.fabricmc.loader.api.FabricLoader;
4343
import net.fabricmc.loader.api.ModContainer;
4444
import net.fabricmc.loader.api.metadata.CustomValue;
45-
import net.fabricmc.loader.api.metadata.ModMetadata;
45+
import net.fabricmc.loader.api.metadata.CustomValue.CvObject;
4646

4747
public class ModList {
4848
private static final Logger LOGGER = LogManager.getLogger();
@@ -115,11 +115,10 @@ private ModFileInfo getModFileByContainer(ModContainer modContainer) {
115115
}
116116

117117
private ModFileInfo createModFileInfo(ModContainer modContainer) {
118-
ModMetadata metadata = modContainer.getMetadata();
119-
120-
// First try to find a patchwork:annotations entry for this file. If it exists, then this is the "primary" mod
118+
CvObject patcherMeta = modContainer.getMetadata().getCustomValue("patchwork:patcher_meta").getAsObject();
119+
// First try to find a patchwork:annotations entry in the patcher metadata. If it exists, then this is the "primary" mod
121120
// for a given JAR file.
122-
CustomValue annotations = metadata.getCustomValue("patchwork:annotations");
121+
CustomValue annotations = patcherMeta.get("annotations");
123122

124123
if (annotations != null) {
125124
String annotationJsonLocation = annotations.getAsString();
@@ -129,7 +128,7 @@ private ModFileInfo createModFileInfo(ModContainer modContainer) {
129128

130129
// If there is no annotation data indicative of a primary mod file, try to then find the parent (primary) mod ID.
131130
// This indicates that this is a dummy JiJ mod created by Patchwork Patcher.
132-
CustomValue parent = metadata.getCustomValue("patchwork:parent");
131+
CustomValue parent = patcherMeta.get("parent");
133132

134133
if (parent != null) {
135134
return getModFileById(parent.getAsString());
@@ -146,7 +145,7 @@ private ModFileInfo createModFileInfo(ModContainer modContainer) {
146145

147146
if (loader.equals("forge")) {
148147
LOGGER.warn("A mod was patched with an old version of Patchwork Patcher, please re-patch it! "
149-
+ "No annotation data is available for " + metadata.getId() + " (loaded from " + modContainer.getRootPath() + ")");
148+
+ "No annotation data is available for " + modContainer.getMetadata().getId() + " (loaded from " + modContainer.getRootPath() + ")");
150149
}
151150
}
152151

src/main/resources/fabric.mod.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
"PatchworkMC"
1414
],
1515
"depends": {
16-
// This is copied over from patchwork-api-base until Loader/201 is resolved properly.
17-
// Loader/204 exists as a bandage fix, but not a real solution.
1816
"fabricloader": ">=0.10.0",
1917
"fabric": ">=0.15.1"
2018
},

0 commit comments

Comments
 (0)