Files
Minecraft-place-mod/src/main/java/com/github/axtps/placemod/mixin/PlaceCommandMixin.java
T
AxTps eba2bdd5e3 feat: 补全 /place structure 的结构注册,使其与自然生成一致
原版 PlaceCommand.placeStructure 只调 StructureStart.placeInChunk 摆放方块,从不把 StructureStart 注册进 StructureManager / 区块 StructureAccess,导致结构重启丢失、专属刷怪规则不激活。

新增 PlaceCommandMixin,在 placeStructure 返回前补做自然生成的三步:1) setStartForStructure 把 start 存进所在区块;2) createReferences 写 17x17 邻居引用;3) markUnsaved 强制存盘。全程 try-catch 兜底,注册失败不影响命令返回。

项目骨架参照 CarpetSLSAddition:Loom 1.18-SNAPSHOT + Gradle 9.7.1 + Java 25 + official 映射。
2026-10-03 15:40:16 +08:00

88 lines
3.9 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.github.axtps.placemod.mixin;
import com.github.axtps.placemod.PlaceMod;
import net.minecraft.core.SectionPos;
import net.minecraft.server.commands.PlaceCommand;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureStart;
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;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
/**
* 让 /place structure 生成的结构"跟自然生成一样"。
*
* 原版 PlaceCommand.placeStructure 只调了 StructureStart.placeInChunk 摆放方块,
* 从不把 StructureStart 注册进 StructureManager / 区块 StructureAccess。
* 结果:结构不进 StructureManager、不写区块 NBT 引用 → 重启丢失、专属刷怪规则不激活。
*
* 本 Mixin 在 placeStructure 返回前,补做自然生成的注册步骤:
* 1. 对结构所在区块 setStartForStructure,把 start 存进区块;
* 2. 调 ChunkGenerator.createReferences 写周围区块引用(跟自然生成同款逻辑);
* 3. markUnsaved 标记涉及的区块,强制存盘。
*/
@Mixin(PlaceCommand.class)
public class PlaceCommandMixin {
@Inject(method = "placeStructure", at = @At("RETURN"), locals = LocalCapture.CAPTURE_FAILHARD)
private static void placemod$registerStructure(net.minecraft.commands.CommandSourceStack source,
net.minecraft.core.Holder.Reference<Structure> structureHolder,
net.minecraft.core.BlockPos pos,
CallbackInfo ci,
ServerLevel level,
Structure structure,
ChunkGenerator generator,
StructureStart start) {
if (start == null || !start.isValid()) {
return;
}
try {
StructureManager structureManager = level.structureManager();
BoundingBox box = start.getBoundingBox();
// 结构包围盒覆盖的区块范围
ChunkPos minChunk = new ChunkPos(
SectionPos.blockToSectionCoord(box.minX()),
SectionPos.blockToSectionCoord(box.minZ()));
ChunkPos maxChunk = new ChunkPos(
SectionPos.blockToSectionCoord(box.maxX()),
SectionPos.blockToSectionCoord(box.maxZ()));
// 1) 把 StructureStart 存进它自己所在的区块
// (自然生成在 ChunkGenerator.createStructures 里做)
ChunkPos startChunk = start.getChunkPos();
ChunkAccess startChunkAccess = level.getChunk(startChunk.x(), startChunk.z());
structureManager.setStartForStructure(
SectionPos.bottomOf(startChunkAccess), structure, start, startChunkAccess);
startChunkAccess.markUnsaved();
// 2) 引用写入:对涉及的每个区块调 createReferences,
// 它内部会扫 17x17 邻居,把相交的 StructureStart 引用写进区块。
// 跟自然生成用的是同一个方法,保证"完全一样"。
ChunkPos.rangeClosed(minChunk, maxChunk).forEach(cp -> {
ChunkAccess chunk = level.getChunk(cp.x(), cp.z());
try {
generator.createReferences(level, structureManager, chunk);
chunk.markUnsaved();
} catch (Exception e) {
PlaceMod.LOGGER.error("[place-mod] createReferences 失败 @ {}: {}", cp, e.toString());
}
});
PlaceMod.LOGGER.info("[place-mod] 已为结构 {} 补注册 StructureStart @ {}",
structure, startChunk);
} catch (Throwable t) {
// 注册失败不能影响命令本身的成功返回
PlaceMod.LOGGER.error("[place-mod] 补注册结构时出错(已忽略): ", t);
}
}
}