Skip to content

Commit e60542d

Browse files
feat(fabric): v26.8-Alpha.3 - TCCL discipline for entrypoint dispatch
Port the thread-context-classloader fix from the neoforge branch (v26.8-Alpha.1): invoke() wraps entrypoint dispatch with TCCL = shared AprismClassLoader, restored in finally. Rationale: ServiceLoader.load() resolves against the TCCL. Without this, any Fabric mod/library performing a META-INF/services lookup during its entrypoint (common in Fabric ecosystem libraries) resolves against the system classloader and finds nothing. GitHub@NDBlockConnect | BlockConnect@StarsailsClover
1 parent 99d9b04 commit e60542d

1 file changed

Lines changed: 21 additions & 0 deletions

File tree

src/main/java/com/aprism/refract/fabric/FabricEntrypointHandler.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ public boolean isExclusive() {
9393
return true;
9494
}
9595

96+
// GitHub@NDBlockConnect | BlockConnect@StarsailsClover
9697
@Override
9798
public void invoke(LoadedModContainer container, AprismPhase phase) {
9899
// Register the mod with the FabricLoader shim (v26.7-Alpha.3) so
@@ -106,6 +107,26 @@ public void invoke(LoadedModContainer container, AprismPhase phase) {
106107
// jar, so its classloader IS the shared class space that also contains
107108
// the mod jars — mod entrypoint classes resolve here.
108109
ClassLoader loader = getClass().getClassLoader();
110+
// TCCL discipline (v26.8-Alpha.3, ported from the neoforge branch):
111+
// mod code must see the shared AprismClassLoader as the thread context
112+
// classloader while it runs — ServiceLoader.load() resolves against
113+
// the TCCL, so without this every mod-side META-INF/services lookup
114+
// (common in Fabric libraries) resolves against the wrong space.
115+
Thread current = Thread.currentThread();
116+
ClassLoader previousTccl = current.getContextClassLoader();
117+
current.setContextClassLoader(loader);
118+
try {
119+
dispatchEntrypoints(container, phase, entrypoints, loader);
120+
} finally {
121+
current.setContextClassLoader(previousTccl);
122+
}
123+
}
124+
125+
/**
126+
* Phase dispatch proper. Runs under the mod-space TCCL.
127+
*/
128+
private void dispatchEntrypoints(LoadedModContainer container, AprismPhase phase,
129+
List<String> entrypoints, ClassLoader loader) {
109130
for (String className : entrypoints) {
110131
try {
111132
Class<?> clazz = Class.forName(className, true, loader);

0 commit comments

Comments
 (0)