AxTps ab5eb31a28
build / build (push) Has been cancelled
海龟就地下蛋mod
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00
2026-10-03 08:40:13 +08:00

Turtle Reproduce — 海龟就地产卵

适用于 Minecraft Java 26.1.2 / Fabric。海龟繁殖后会寻找当前位置附近最近水源边、能够走到的沙地,直接挖沙产卵,不再为了产卵返回出生地。

📌 本副本基于上游源文件修改:只对热路径做了一处性能优化,玩法行为不变(不做成成品 mod 分发,只提供工程源码)。 改动清单见文末「本副本的改动(相对上游源文件)」,逐行 diff 见 OPTIMIZATION.diff。

行为规则

  • 从海龟当前位置搜索 X/Z 各 ±32 格、Y ±8 格的已加载区域,不主动加载或生成新区块。
  • 沙地须上方为空气,且水平 4 格半径、垂直 ±1 格内有露出水面的静止水源。普通沙子和红沙均适用;流动水及含水方块不算水源。
  • 优先选择距离海龟最近的水源对应的沙地;对应同一水源时,选择距离海龟最近的可达沙地。被墙挡住、站立空间不足的位置会跳过。
  • 保留原版挖沙动画、产卵数量(1~4 枚)、繁殖冷却和孵化机制。
  • 找不到合适地点时,海龟保留腹中的蛋并稍后重试。可在附近补上水源和沙地。
  • 不改写海龟的出生地数据;没有携带蛋时的普通活动保留原版行为。

安装

需要 Java 25 或更高版本、Fabric Loader 0.19.5 或更高版本,以及适用于 26.1.2 的 Fabric API、Fabric Language Kotlin。

本包已随附编译好的成品 build/libs/turtle-reproduce-1.0.0.jar(由本包源码构建,20,528 字节,SHA-256 f61e53d152dd2722a4dda31d63cd8fedd201af312d5fce03bc4a3c8c36e704b6),可直接使用,无需自行编译。

将 build/libs/turtle-reproduce-1.0.0.jar 放入游戏实例或服务器的 mods 文件夹,不要安装 -sources.jar。

单人游戏安装到客户端。多人游戏安装到服务器即可,玩家客户端不需要安装本模组。

构建与测试

使用 JDK 25,在项目目录运行:

.\gradlew.bat build

Linux / macOS:

./gradlew build

如果终端默认使用 Java 21,先将当前终端的 JAVA_HOME 指向 JDK 25。IntelliJ IDEA 中也应把 Gradle JVM 设置为 25。

服务器游戏测试:

.\gradlew.bat runGameTest

build 会自动运行服务器游戏测试,也可用上面的命令单独运行。测试在独立世界覆盖真实繁殖、异地产卵、最近水岸、16 格外水岸、绕过封闭水岸、无沙地保留蛋、无水沙地拒绝产卵以及身体触水时选择干燥位置。测试代码不打包进发布模组。

手动体验时,可将两只海龟带离出生海滩,在新地点修建开阔沙岸和水池,用海草喂食繁殖。怀卵海龟应在新沙岸挖沙产卵。注意让沙岸足够宽,保留海龟进出水面的通道。

本副本的改动(相对上游源文件)

本副本以上游源文件为基础,改动只集中在一个文件,目的是降低服务端开销;玩法规则、判定条件、数值与数据格式一律未变。

项 内容
改动文件 src/main/java/com/mr/ai/NestingSiteFinder.java(唯一被改动的文件)
未改动 4 个 mixin(TurtleLayEggGoalMixin、TurtleGoHomeGoalMixin、TurtleAccessor、PathNavigationAccessor)、Kotlin 入口、fabric.mod.json、turtle-reproduce.mixins.json、src/client、全部 GameTest
逐行 diff OPTIMIZATION.diff(+146 / −35 行)

为什么要改

NestingSiteFinder.findCandidates 是热点:单次调用要扫 73 × 73 列 × 19 层 ≈ 10.1 万个方块,而怀卵海龟只要偏离上次搜索原点超过 4 格、或把候选列表消费完,就会整片重扫。原实现每个方块都调用一次 Level#getBlockState(内部要重新解析区块、段索引与建筑高度),并为每块沙新建一个 BlockPos 对象。

具体改动

  1. 按区块段读方块,整段跳过空气段:改走 ChunkAccess#getSections() + LevelChunkSection#getBlockState();对 hasOnlyAir() 的段整段跳过。空段里只可能是空气,不可能提供水源或沙地,因此跳过它读不到任何会成为候选的方块。
  2. 区块解析次数由 5329 次降到 ≤36 次:循环由「列 → 层」改为「区块 → 段 → 方块」,每列只解析一次区块。原来的 Level#hasChunk(x >> 4, z >> 4) 换成等价的 Level#getChunk(cx, cz, ChunkStatus.FULL, false)——hasChunk 内部正是这个调用;loadOrGenerate = false,依然绝不加载或生成区块。
  3. 沙地候选改用打包 long:ArrayList<BlockPos> → fastutil LongArrayList(BlockPos.asLong / getX|getY|getZ(long)),一次扫描不再产生成千上万个临时对象。
  4. isValidSite 去掉重复查询:提取循环不变量(方块坐标、建筑高度判定),并记住上一个查询过的区块可用性——半径 4 的圆盘最多跨 4 个区块。

为什么行为不变

  • 搜索盒子的范围(X/Z ±32 加 4 格水源外扩、Y ±8 加 ±1)以及每一项判定条件与短路顺序逐条保留。
  • 候选最终由同一个比较器排序,而它以沙地 x/y/z 结尾,构成全序(不同位置永不相等)。因此结果与扫描的访问顺序无关,排序后的候选列表逐位相同。
  • javap 比对:公开方法签名、4 个公开常量值(SEARCH_RADIUS = 32、VERTICAL_SEARCH_RADIUS = 8、WATER_RADIUS = 4、WATER_VERTICAL_RADIUS = 1)以及 Candidate 记录的成员完全一致;唯一差异是一个 private 辅助方法的签名,故其余 class(含 4 个 mixin)的链接关系不受影响。
  • 常量池比对:新增的类型引用只有原版 Minecraft 与 fastutil 的类,没有引入任何新的运行期依赖。

验证情况

项 状态
编译 ✅ JDK 25,javac --release 25;class 文件版本 69,与上游构建一致
字节码 ✅ javap 确认新逻辑(getSections / hasOnlyAir / LongArrayList#getLong / getChunk(..., false))已进入产物
链接 ✅ 以真实 Minecraft 26.1.2 + Fabric API + fastutil 作为 classpath 做 Class.forName 反射检查,成员列表与上游逐条一致
游戏内实测 ✅ Minecraft 26.1.2 单机:怀卵海龟在本地水岸沙地产卵、蛋数 1~4、home_pos 未被改写、距出生地数千格仍能就地产卵
7 个 GameTest ⚠️ 未在本机执行(需要完整 Loom 构建并联网拉取依赖)。行为等价性由上述静态论证 + 游戏内实测支撑,建议在能联网的环境跑一次 .\gradlew.bat build 复核

许可

CC0-1.0。

S
Description
让海龟就地下蛋,by Mr_dayhappy,已集成到slsa
Readme
102 KiB
0 Stars 1 Watchers 0 Forks
Languages
Java 97.3%
Kotlin 2.7%