Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 3 additions & 22 deletions versions/1.20.1/java/src/main/java/wg/CppWorldgen.java
Original file line number Diff line number Diff line change
Expand Up @@ -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("worldgen-bench").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 数据目录) */
Expand Down
199 changes: 199 additions & 0 deletions versions/1.20.1/java/src/main/java/wg/bench/CoreSwapFixHelper.java
Original file line number Diff line number Diff line change
@@ -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<JarEntry> 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<ModContainer>
for (Object mc : (Iterable<?>) mods) {
Object origin = mc.getClass().getMethod("getOrigin").invoke(mc); // ModOrigin
Object paths = origin.getClass().getMethod("getPaths").invoke(origin); // List<Path>
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<URL> 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<JarEntry> 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<Path> stream = Files.walk(path)) {
stream.sorted(Comparator.reverseOrder()).forEach(p -> {
try {
Files.deleteIfExists(p);
}
catch (IOException ignored) {
// best effort
}
});
}
}
}
40 changes: 3 additions & 37 deletions versions/1.20.1/java/src/main/java/wg/bench/CppBridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,43 +39,9 @@ public static void init(long seed) {
* <tmp>/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 {
Expand Down