diff --git a/gradle.properties b/gradle.properties index 2e93d86..3813ea0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -46,8 +46,8 @@ mod_description=Multi-threaded dimension parallel optimization: independent per- # Proxy settings for VPN / system proxy # 说明:VPN 开启(系统代理模式)时取消下面 4 行注释;直连可访问时保持注释状态 -#systemProp.http.proxyHost=127.0.0.1 -#systemProp.http.proxyPort=57777 -#systemProp.https.proxyHost=127.0.0.1 -#systemProp.https.proxyPort=57777 -#systemProp.http.nonProxyHosts=localhost|127.*|192.168.*|10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.* +systemProp.http.proxyHost=127.0.0.1 +systemProp.http.proxyPort=7897 +systemProp.https.proxyHost=127.0.0.1 +systemProp.https.proxyPort=7897 +systemProp.http.nonProxyHosts=localhost|127.*|192.168.*|10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.* diff --git a/src/main/java/dev/modzuozhi/mixin/DimensionalRipperMixinPlugin.java b/src/main/java/dev/modzuozhi/mixin/DimensionalRipperMixinPlugin.java index 9d68b73..ed003f0 100644 --- a/src/main/java/dev/modzuozhi/mixin/DimensionalRipperMixinPlugin.java +++ b/src/main/java/dev/modzuozhi/mixin/DimensionalRipperMixinPlugin.java @@ -11,20 +11,30 @@ import java.util.Set; /** Selects compatibility-safe mixins before Minecraft target classes are transformed. */ public final class DimensionalRipperMixinPlugin implements IMixinConfigPlugin { private boolean lithiumLoaded; + private boolean c2meLoaded; @Override public void onLoad(String mixinPackage) { try { var loadingMods = FMLLoader.getLoadingModList(); this.lithiumLoaded = loadingMods != null && loadingMods.getModFileById("lithium") != null; + this.c2meLoaded = loadingMods != null && loadingMods.getModFileById("c2me") != null; } catch (Throwable ignored) { // If loader discovery is unavailable, preserve the standalone behavior. this.lithiumLoaded = false; + this.c2meLoaded = false; } } @Override public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + // C2ME's fixes-worldgen-threading-issues module redirects the same Level. random + // source injection point with a higher priority (1100), which would silently skip ours and + // trip defaultRequire=1. Its CheckedThreadLocalRandom is compatible with our thread swapping, + // so let it own the injection point whenever C2ME is present. + if (mixinClassName.endsWith(".LevelRandomMixin")) { + return !this.c2meLoaded; + } if (mixinClassName.endsWith(".LithiumEntityGroupsMixin")) { return this.lithiumLoaded; } diff --git a/src/main/java/dev/modzuozhi/mixin/LevelMixin.java b/src/main/java/dev/modzuozhi/mixin/LevelMixin.java index 24a7a9f..c4602ed 100644 --- a/src/main/java/dev/modzuozhi/mixin/LevelMixin.java +++ b/src/main/java/dev/modzuozhi/mixin/LevelMixin.java @@ -2,7 +2,6 @@ package dev.modzuozhi.mixin; import dev.modzuozhi.core.dimthread.DimThreadCore; import dev.modzuozhi.core.dimthread.FineGrainScheduler; -import net.minecraft.util.RandomSource; import net.minecraft.world.level.Level; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -27,22 +26,6 @@ public abstract class LevelMixin { @Shadow public Thread thread; - /** - * 将 {@code Level.random}(及 {@code randValue})初始化为线程安全随机源。 - *

- * 原版 {@code Level.random = RandomSource.create()} 得到 {@code LegacyRandomSource}, - * 其内部通过 {@code ThreadingDetector} 检测跨线程访问并抛异常。维度并行/细粒度并行下, - * 实体 AI(村民、群游鱼等)与服务器主线程会并发访问 {@code getRandom()},导致 - * "Accessing LegacyRandomSource from multiple threads"。这里重定向构造期间的 - * {@code RandomSource.create()} 为 {@code createThreadSafe()}({@code ThreadSafeLegacyRandomSource}, - * 基于 AtomicLong CAS,无线程检测),使并发访问安全。 - */ - @Redirect(method = "", - at = @At(value = "INVOKE", target = "Lnet/minecraft/util/RandomSource;create()Lnet/minecraft/util/RandomSource;")) - private static RandomSource modzuozhi_threadSafeRandom() { - return RandomSource.createThreadSafe(); - } - @Redirect(method = "getBlockEntity", at = @At(value = "INVOKE", target = "Ljava/lang/Thread;currentThread()Ljava/lang/Thread;")) private Thread modzuozhi_recallForDimthreads() { diff --git a/src/main/java/dev/modzuozhi/mixin/LevelRandomMixin.java b/src/main/java/dev/modzuozhi/mixin/LevelRandomMixin.java new file mode 100644 index 0000000..6bd780f --- /dev/null +++ b/src/main/java/dev/modzuozhi/mixin/LevelRandomMixin.java @@ -0,0 +1,40 @@ +package dev.modzuozhi.mixin; + +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.Level; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +/** + * 将 {@code Level.random}(及 {@code randValue})初始化为线程安全随机源。 + *

+ * 原版 {@code Level.random = RandomSource.create()} 得到 {@code LegacyRandomSource}, + * 其内部通过 {@code ThreadingDetector} 检测跨线程访问并抛异常。维度并行/细粒度并行下, + * 实体 AI(村民、群游鱼等)与服务器主线程会并发访问 {@code getRandom()},导致 + * "Accessing LegacyRandomSource from multiple threads"。这里重定向构造期间的 + * {@code RandomSource.create()} 为 {@code createThreadSafe()}({@code ThreadSafeLegacyRandomSource}, + * 基于 AtomicLong CAS,无线程检测),使并发访问安全。 + *

+ * 与 C2ME 的兼容:C2ME 的 {@code fixes-worldgen-threading-issues} 模块对同一个 + * {@code Level.} 注入点做 {@code @Redirect}(返回其 {@code CheckedThreadLocalRandom}), + * 且 C2ME 的 {@code mixinPriority=1100} 高于本模组默认的 1000。若两边同时应用,本模组的 + * 重定向会被静默跳过,而 {@code defaultRequire=1} 会导致注入检查失败、启动崩溃。 + *

+ * 因此本 mixin 被拆为独立类,由 {@code DimensionalRipperMixinPlugin} 在检测到 C2ME 加载时 + * 整体跳过(返回 false)。C2ME 的 {@code CheckedThreadLocalRandom} 以 {@code () -> this.thread} + * 做归属校验,而本模组的 {@code swapThreadsAndRun} 会把 {@code Level.thread} 与当前 worker + * 一并替换,两者方向一致,故 C2ME 的随机源在维度并行下同样安全 —— 让出此注入点不影响 + * 本模组的并发正确性,也保留了独立的 {@code createThreadSafe()} 行为(C2ME 不在时)。 + *

+ * 注意:{@code LevelMixin} 中的 {@code getBlockEntity} 线程守卫伪装与本类无关,永远应用。 + */ +@Mixin(Level.class) +public abstract class LevelRandomMixin { + + @Redirect(method = "", + at = @At(value = "INVOKE", target = "Lnet/minecraft/util/RandomSource;create()Lnet/minecraft/util/RandomSource;")) + private static RandomSource modzuozhi_threadSafeRandom() { + return RandomSource.createThreadSafe(); + } +} \ No newline at end of file diff --git a/src/main/resources/dimensionalripper.mixins.json b/src/main/resources/dimensionalripper.mixins.json index 5d9a908..2bc3880 100644 --- a/src/main/resources/dimensionalripper.mixins.json +++ b/src/main/resources/dimensionalripper.mixins.json @@ -37,6 +37,7 @@ "LevelExplodeMixin", "LevelGetChunkMixin", "LevelMixin", + "LevelRandomMixin", "LevelTicksMixin", "LivingEntityGetInBlockStateMixin", "MinecraftServerDimMixin",