From 9168e10ec29d5a982b477077cd9aea897723b2e8 Mon Sep 17 00:00:00 2001 From: dustinmoon78 Date: Thu, 6 Aug 2026 14:25:30 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20CppWorldgen=20=E6=BC=8F=E6=94=B9=20m?= =?UTF-8?q?od=20id=20worldgen-bench=E2=86=92coreswap=EF=BC=881.0.4=20?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E5=B4=A9=E6=BA=83=E6=A0=B9=E5=9B=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CppBridge.java 已在上次修复(ca87548)改为 coreswap, 但 CppWorldgen.extractNativeDll() 仍硬编码 worldgen-bench, FabricLoader.getModContainer().get() 抛 NoSuchElementException, 全新环境解压 worldgen.dll 时启动崩溃。 --- versions/1.20.1/java/src/main/java/wg/CppWorldgen.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions/1.20.1/java/src/main/java/wg/CppWorldgen.java b/versions/1.20.1/java/src/main/java/wg/CppWorldgen.java index 79f121a..9daab6e 100644 --- a/versions/1.20.1/java/src/main/java/wg/CppWorldgen.java +++ b/versions/1.20.1/java/src/main/java/wg/CppWorldgen.java @@ -33,7 +33,7 @@ private static String extractNativeDll() { try { if (!Files.exists(dll)) { Files.createDirectories(dir); - var container = FabricLoader.getInstance().getModContainer("worldgen-bench").get(); + var container = FabricLoader.getInstance().getModContainer("coreswap").get(); for (Path root : container.getRootPaths()) { Path src = root.resolve("native/worldgen.dll"); if (Files.isRegularFile(src)) { From 75b9e75585b0292e734bc510f87f3b8c5bfb39f5 Mon Sep 17 00:00:00 2001 From: dustinmoon78 Date: Thu, 6 Aug 2026 14:28:43 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20Forge+Connector=20=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=20=E2=80=94=E2=80=94=20=E8=B5=84=E6=BA=90=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E6=94=B9=20CoreSwapFixHelper=20=E5=A4=9A=E7=BA=A7?= =?UTF-8?q?=E5=AE=9A=E4=BD=8D=20jar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原 extractWorldgenDir/extractNativeDll 依赖 FabricLoader.getRootPaths(), 在 Forge 宿主 + Sinytra Connector 环境下(Forge UnionFileSystem 的 Path 无法 Files.isDirectory/walk;Forge TransformingClassLoader 下 getCodeSource() 返回 /)资源提取失败。 新增 wg/bench/CoreSwapFixHelper:多级定位 mod jar (getCodeSource → FabricLoader.getAllMods().ModOrigin.getPaths() → ClassLoader.getResources),JarFile 直接提取 worldgen-data / worldgen.dll, 不依赖任何加载器路径 API。实测 Forge 47.3.33 + Connector 1.0.0-beta.46 可正常生成。 --- .../java/src/main/java/wg/CppWorldgen.java | 25 +-- .../main/java/wg/bench/CoreSwapFixHelper.java | 199 ++++++++++++++++++ .../src/main/java/wg/bench/CppBridge.java | 40 +--- 3 files changed, 205 insertions(+), 59 deletions(-) create mode 100644 versions/1.20.1/java/src/main/java/wg/bench/CoreSwapFixHelper.java diff --git a/versions/1.20.1/java/src/main/java/wg/CppWorldgen.java b/versions/1.20.1/java/src/main/java/wg/CppWorldgen.java index 9daab6e..6b6d8c2 100644 --- a/versions/1.20.1/java/src/main/java/wg/CppWorldgen.java +++ b/versions/1.20.1/java/src/main/java/wg/CppWorldgen.java @@ -27,28 +27,9 @@ public final class CppWorldgen { private CppWorldgen() {} private static String extractNativeDll() { - String tmpDir = System.getProperty("java.io.tmpdir"); - Path dir = Path.of(tmpDir, "coreswap-native"); - Path dll = dir.resolve("worldgen.dll"); - try { - if (!Files.exists(dll)) { - Files.createDirectories(dir); - var container = FabricLoader.getInstance().getModContainer("coreswap").get(); - for (Path root : container.getRootPaths()) { - Path src = root.resolve("native/worldgen.dll"); - if (Files.isRegularFile(src)) { - Files.copy(src, dll, StandardCopyOption.REPLACE_EXISTING); - break; - } - } - } - if (!Files.exists(dll)) { - throw new IllegalStateException("worldgen.dll not found in mod native/"); - } - return dll.toString(); - } catch (IOException e) { - throw new RuntimeException("failed to extract worldgen.dll", e); - } + // Forge+Connector 兼容:原 getRootPaths() 在 Forge UnionFileSystem 下不可遍历, + // 改用 CoreSwapFixHelper 多级定位 jar(codeSource → ModOrigin.getPaths → classloader)后 JarFile 提取。 + return CoreSwapFixHelper.extractNativeDll(); } /** 创建 worldgen 句柄(seed + worldgen JSON 数据目录) */ diff --git a/versions/1.20.1/java/src/main/java/wg/bench/CoreSwapFixHelper.java b/versions/1.20.1/java/src/main/java/wg/bench/CoreSwapFixHelper.java new file mode 100644 index 0000000..6a83984 --- /dev/null +++ b/versions/1.20.1/java/src/main/java/wg/bench/CoreSwapFixHelper.java @@ -0,0 +1,199 @@ +package wg.bench; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.stream.Stream; + +/** + * CoreSwap fix helper (3rd round). + * + * 原版用 FabricLoader.getModContainer("...").getRootPaths() 遍历 mod 资源, + * 在 Sinytra Connector(Forge 宿主)环境下:Forge 的 SecureJar/UnionFileSystem + * 返回的 root Path 无法被 Files.isDirectory / Files.walk 正常解析; + * 而 getProtectionDomain().getCodeSource().getLocation() 对 Forge + * TransformingClassLoader 加载的类返回 "/"(无具体 jar)。 + * + * 本类改为多级定位「包含资源的 jar」并直接用 JarFile 提取: + * 1. getCodeSource()(纯 Fabric 环境) + * 2. FabricLoader.getAllMods() → ModOrigin.getPaths()(Forge+Connector, + * 返回 ModFile.getFilePath() 的磁盘 jar 路径;反射调用避免编译依赖) + * 3. ClassLoader.getResources("worldgen-data") 资源枚举兜底 + */ +public final class CoreSwapFixHelper { + private CoreSwapFixHelper() { + } + + /** 替换 wg.bench.CppBridge.extractWorldgenDir() 的调用目标。 */ + public static String extractWorldgenDir() { + String tmpDir = System.getProperty("java.io.tmpdir"); + Path target = Path.of(tmpDir, "coreswap-data"); + Path wgDir = target.resolve("worldgen"); + Path marker = wgDir.resolve("data/minecraft/worldgen/noise_settings/overworld.json"); + try { + if (!Files.exists(marker)) { + if (Files.exists(target)) { + deleteRecursively(target); + } + Files.createDirectories(wgDir); + extractFromJar("worldgen-data", target, wgDir); + if (!Files.exists(marker)) { + throw new IllegalStateException("worldgen-data not found in mod resources"); + } + } + return wgDir.toString(); + } + catch (RuntimeException e) { + throw e; + } + catch (Exception e) { + throw new RuntimeException("failed to extract worldgen-data", e); + } + } + + /** 替换 wg.CppWorldgen.extractNativeDll() 的调用目标。 */ + public static String extractNativeDll() { + String tmpDir = System.getProperty("java.io.tmpdir"); + Path dir = Path.of(tmpDir, "coreswap-native"); + Path dll = dir.resolve("worldgen.dll"); + try { + if (!Files.exists(dll)) { + Files.createDirectories(dir); + extractFromJar("native", dir, dir); + } + if (!Files.exists(dll)) { + throw new IllegalStateException("worldgen.dll not found in mod native/"); + } + return dll.toString(); + } + catch (IOException e) { + throw new RuntimeException("failed to extract worldgen.dll", e); + } + } + + /** + * 从定位到的 jar 提取 prefix/ 下的所有文件。 + * 布局与原版一致:rel 以 "data" 开头 → wgDir 下;否则 → target 下。 + */ + private static void extractFromJar(String prefix, Path target, Path wgDir) throws IOException { + Path jarPath = locateJar(); + if (jarPath == null || !Files.isRegularFile(jarPath)) { + throw new IOException("cannot locate mod jar for resource extraction (tried codeSource, ModOrigin, classloader): " + jarPath); + } + try (JarFile jf = new JarFile(jarPath.toFile())) { + Enumeration en = jf.entries(); + while (en.hasMoreElements()) { + JarEntry e = en.nextElement(); + if (e.isDirectory()) continue; + String name = e.getName(); + if (!name.startsWith(prefix + "/")) continue; + String rel = name.substring(prefix.length() + 1); + Path dst = rel.startsWith("data") ? wgDir.resolve(rel) : target.resolve(rel); + if (dst.getParent() != null) { + Files.createDirectories(dst.getParent()); + } + try (InputStream in = jf.getInputStream(e)) { + Files.copy(in, dst, StandardCopyOption.REPLACE_EXISTING); + } + } + } + } + + /** 多级定位包含 mod 资源的 jar。 */ + private static Path locateJar() { + // 1) code source(纯 Fabric 环境) + try { + URL loc = CoreSwapFixHelper.class.getProtectionDomain().getCodeSource().getLocation(); + Path p = toPath(loc); + if (p != null && Files.isRegularFile(p)) { + return p; + } + } + catch (Exception ignored) { + } + // 2) FabricLoader mods → ModOrigin.getPaths()(Forge+Connector 返回磁盘 jar 路径) + try { + Class loaderCls = Class.forName("net.fabricmc.loader.api.FabricLoader"); + Object loader = loaderCls.getMethod("getInstance").invoke(null); + Object mods = loader.getClass().getMethod("getAllMods").invoke(loader); // Collection + for (Object mc : (Iterable) mods) { + Object origin = mc.getClass().getMethod("getOrigin").invoke(mc); // ModOrigin + Object paths = origin.getClass().getMethod("getPaths").invoke(origin); // List + for (Object o : (Iterable) paths) { + Path p = (Path) o; + if (Files.isRegularFile(p) && jarContains(p, "worldgen-data")) { + return p; + } + } + } + } + catch (Exception ignored) { + } + // 3) classloader 资源枚举兜底 + try { + Enumeration urls = CoreSwapFixHelper.class.getClassLoader().getResources("worldgen-data"); + while (urls.hasMoreElements()) { + Path p = toPath(urls.nextElement()); + if (p != null && Files.isRegularFile(p)) { + return p; + } + } + } + catch (Exception ignored) { + } + return null; + } + + /** 快速检查 jar 是否包含某前缀资源。 */ + private static boolean jarContains(Path jarPath, String prefix) { + try (JarFile jf = new JarFile(jarPath.toFile())) { + Enumeration en = jf.entries(); + while (en.hasMoreElements()) { + if (en.nextElement().getName().startsWith(prefix + "/")) { + return true; + } + } + } + catch (IOException ignored) { + } + return false; + } + + /** URL → 磁盘 Path;兼容 jar:file:/...!/ 形式。 */ + private static Path toPath(URL loc) { + if (loc == null) return null; + try { + String s = loc.toString(); + if (s.startsWith("jar:")) { + int idx = s.indexOf("!/"); + if (idx >= 0) s = s.substring(4, idx); + loc = new URL(s); + } + return Path.of(loc.toURI()); + } + catch (Exception e) { + return null; + } + } + + private static void deleteRecursively(Path path) throws IOException { + if (!Files.exists(path)) return; + try (Stream stream = Files.walk(path)) { + stream.sorted(Comparator.reverseOrder()).forEach(p -> { + try { + Files.deleteIfExists(p); + } + catch (IOException ignored) { + // best effort + } + }); + } + } +} diff --git a/versions/1.20.1/java/src/main/java/wg/bench/CppBridge.java b/versions/1.20.1/java/src/main/java/wg/bench/CppBridge.java index 7de1fd0..b4edca0 100644 --- a/versions/1.20.1/java/src/main/java/wg/bench/CppBridge.java +++ b/versions/1.20.1/java/src/main/java/wg/bench/CppBridge.java @@ -39,43 +39,9 @@ public static void init(long seed) { * /coreswap-data/blocks.json / biome_params.json (wgDir/../ 查找) */ private static String extractWorldgenDir() { - String tmpDir = System.getProperty("java.io.tmpdir"); - Path target = Path.of(tmpDir, "coreswap-data"); - Path wgDir = target.resolve("worldgen"); - try { - Path marker = wgDir.resolve("data/minecraft/worldgen/noise_settings/overworld.json"); - if (!Files.exists(marker)) { - // 幂等失败时残留旧结构 → 先清再解压 - if (Files.exists(target)) deleteRecursively(target); - Files.createDirectories(wgDir); - // mod id 已改名 coreswap(1.0.0+);改名时务必同步这里,否则全新环境解压数据时 Optional.get() 抛 NoSuchElementException 崩溃(CppBridge.java:51 历史坑) - var container = net.fabricmc.loader.api.FabricLoader.getInstance().getModContainer("coreswap").get(); - for (Path root : container.getRootPaths()) { - Path src = root.resolve("worldgen-data"); - if (!Files.isDirectory(src)) continue; - try (var stream = Files.walk(src)) { - stream.filter(p -> Files.isRegularFile(p)).forEach(p -> { - Path rel = src.relativize(p); // data/... 或 blocks.json / biome_params.json - Path dst = rel.startsWith("data") ? wgDir.resolve(rel.toString()) : target.resolve(rel.toString()); - try { - Files.createDirectories(dst.getParent()); - Files.copy(p, dst, java.nio.file.StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } - } - if (!Files.exists(marker)) { - throw new IllegalStateException("worldgen-data not found in mod resources"); - } - } - return wgDir.toString(); - } catch (RuntimeException e) { - throw e; - } catch (Exception e) { - throw new RuntimeException("failed to extract worldgen-data", e); - } + // Forge+Connector 兼容:原 getRootPaths() 在 Forge UnionFileSystem 下不可遍历, + // 改用 CoreSwapFixHelper 多级定位 jar(codeSource → ModOrigin.getPaths → classloader)后 JarFile 提取。 + return CoreSwapFixHelper.extractWorldgenDir(); } private static void deleteRecursively(Path path) throws IOException {