Skip to content

Commit

Permalink
Avoid split package issue when packaging EMI API classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Su5eD committed Sep 16, 2023
1 parent 8a274bf commit 0db7327
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 5 deletions.
18 changes: 18 additions & 0 deletions emi-bridge/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import net.fabricmc.loom.util.FileSystemUtil
import java.nio.file.Files
import java.nio.file.StandardCopyOption

plugins {
id("dev.architectury.loom")
}
Expand Down Expand Up @@ -34,3 +38,17 @@ dependencies {

modImplementation(group = "dev.emi", name = "emi-forge", version = "1.0.19+1.20.1")
}

tasks.remapJar {
// Painfully move dev/emi into relocate/dev/emi - gradle does NOT make this easy ...
doLast {
FileSystemUtil.getJarFileSystem(archiveFile.get().asFile.toPath(), false).use { fs ->
val from = fs.getPath("dev/emi")
val to = fs.getPath("relocate/dev/emi")
Files.walk(from).forEach {
Files.move(it, to.resolve(from.relativize(it)).also { Files.createDirectories(it.parent) }, StandardCopyOption.COPY_ATTRIBUTES)
}
Files.walk(from).sorted(Comparator.reverseOrder()).forEach(Files::delete)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,99 @@
package dev.su5ed.sinytra.connectorextras.emibridge;

import com.mojang.logging.LogUtils;
import cpw.mods.jarhandling.SecureJar;
import cpw.mods.modlauncher.Launcher;
import cpw.mods.modlauncher.api.IModuleLayerManager;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.unsafe.UnsafeHacks;
import org.slf4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleReference;
import java.lang.module.ResolvedModule;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.CodeSigner;
import java.util.Map;
import java.util.Optional;
import java.util.jar.Manifest;

@Mod("connectorextras_emi_bridge")
public class EMIBridge {
private static final Logger LOGGER = LogUtils.getLogger();

public static void injectModule() {
try {
ModuleLayer layer = Launcher.INSTANCE.findLayerManager().orElseThrow().getLayer(IModuleLayerManager.Layer.GAME).orElseThrow();
ResolvedModule emiModule = layer.configuration().findModule("emi").orElse(null);
if (emiModule == null) {
LOGGER.debug("EMI is not present, skipping class injection");
return;
}

Class<?> jarModuleReference = Class.forName("cpw.mods.cl.JarModuleFinder$JarModuleReference");
ModuleReference reference = emiModule.reference();
if (!jarModuleReference.isInstance(reference)) {
LOGGER.error("EMI module does not contain a jar module reference");
return;
}

Field jarField = jarModuleReference.getDeclaredField("jar");
SecureJar.ModuleDataProvider originalProvider = UnsafeHacks.getField(jarField, reference);
Path relocatePath = getRelocatedClassesPath();
if (relocatePath == null) {
LOGGER.error("EMI API relocated path not found");
return;
}
SecureJar.ModuleDataProvider wrappedProvider = new ModuleDataProviderWrapper(originalProvider, relocatePath);
UnsafeHacks.setField(jarField, reference, wrappedProvider);

LOGGER.debug("Successfully injected EMI Fabric API classes");
} catch (Throwable t) {
LOGGER.error("Error injecting EMI Fabric API classes", t);
}
}

public static Path getRelocatedClassesPath() throws URISyntaxException, IOException {
URL relocateUrl = EMIBridge.class.getResource("/relocate");
if (relocateUrl != null) {
Path relocatePath = Path.of(relocateUrl.toURI());
URI pathFsUri = new URI("path://" + relocateUrl.getPath());
FileSystem pathFS = FileSystems.newFileSystem(pathFsUri, Map.of("packagePath", relocatePath));
return pathFS.getPath("/");
}
return null;
}

public record ModuleDataProviderWrapper(SecureJar.ModuleDataProvider provider, Path relocatePath) implements SecureJar.ModuleDataProvider {
@Override
public Optional<InputStream> open(String name) {
return provider.open(name)
.or(() -> {
try {
Path path = relocatePath.resolve(name);
return Optional.of(Files.newInputStream(path));
} catch (Exception ignored) {
}
return Optional.empty();
});
}

//@formatter:off
@Override public String name() {return provider.name();}
@Override public ModuleDescriptor descriptor() {return provider.descriptor();}
@Override public URI uri() {return provider.uri();}
@Override public Optional<URI> findFile(String name) {return provider.findFile(name);}
@Override public Manifest getManifest() {return provider.getManifest();}
@Override public CodeSigner[] verifyAndGetSigners(String cname, byte[] bytes) {return provider.verifyAndGetSigners(cname, bytes);}
//@formatter:on
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ public class EmiAgnosForgeMixin {
@ModifyVariable(method = "getPluginsAgnos", at = @At("RETURN"), remap = false)
private List<EmiPluginContainer> connectorextras_emi_bridge$addFabricPlugins(List<EmiPluginContainer> orig) {
orig.addAll(FabricLoader.getInstance()
.getEntrypointContainers("emi", EmiPlugin.class)
.stream()
.map(p -> new EmiPluginContainer(p.getEntrypoint(), p.getProvider().getMetadata().getId()))
.toList());
.getEntrypointContainers("emi", EmiPlugin.class)
.stream()
.map(p -> new EmiPluginContainer(p.getEntrypoint(), p.getProvider().getMetadata().getId()))
.toList());
return orig;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dev.su5ed.sinytra.connectorextras.emibridge.mixin;

import dev.su5ed.sinytra.connectorextras.emibridge.EMIBridge;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin({net.minecraft.client.main.Main.class, net.minecraft.server.Main.class})
public class MainEntrypointMixin {
@Inject(method = "main", at = @At("HEAD"), remap = false)
private static void beforeGameLaunch(String[] strings, CallbackInfo ci) {
EMIBridge.injectModule();
}
}
3 changes: 2 additions & 1 deletion emi-bridge/src/main/resources/mixins.emibridge.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"required": true,
"package": "dev.su5ed.sinytra.connectorextras.emibridge.mixin",
"mixins": [
"EmiAgnosForgeMixin"
"EmiAgnosForgeMixin",
"MainEntrypointMixin"
]
}

0 comments on commit 0db7327

Please sign in to comment.