Skills/nms/nms-chunk-access/SKILL.md
透過 NMS LevelChunk 直接讀寫方塊、高度圖、ChunkSection 資料,比 Bukkit Chunk API 更快更底層(Paper NMS + Mojang-mapped)/ Direct LevelChunk block, heightmap, and ChunkSection access for high-performance operations
npx skillsauth add MrPippi/MPS nms-chunk-accessInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
nms-chunk-access
透過 NMS LevelChunk、ChunkAccess、LevelChunkSection 直接讀寫方塊狀態與高度圖,繞過 Bukkit Chunk.getBlock() 的逐格開銷,實現高效能的大範圍方塊操作(如結構生成、地圖掃描)。
| 參數 | 範例 | 說明 |
|------|------|------|
| package_name | com.example.world | 產出類別所在 package |
| class_name | ChunkAccessUtil | 工具類名稱 |
ChunkAccessUtil.java — LevelChunk 讀寫工具BulkBlockEditor.java — 批次方塊操作(最小化客戶端更新)參見 Skills/paper-nms/PLATFORM.md。關鍵依賴:
dependencies {
paperweight.paperDevBundle('1.21.1-R0.1-SNAPSHOT')
}
ChunkAccessUtil.javapackage com.example.world;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.levelgen.Heightmap;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_21_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
@SuppressWarnings("UnstableApiUsage")
public final class ChunkAccessUtil {
private ChunkAccessUtil() {}
/** 取得 NMS LevelChunk。 */
public static LevelChunk getChunk(Chunk chunk) {
return ((CraftChunk) chunk).getHandle(net.minecraft.world.level.chunk.status.ChunkStatus.FULL);
}
/** 取得指定世界座標的 NMS BlockState(不觸發光照更新)。 */
public static BlockState getBlockState(Location loc) {
net.minecraft.world.level.Level level = ((CraftWorld) loc.getWorld()).getHandle();
BlockPos pos = new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
return level.getChunk(pos).getBlockState(pos);
}
/**
* 直接設定方塊狀態(跳過部分 Bukkit 處理,效能較高)。
* flags: 1=update neighbors, 2=send to clients, 3=both
* 必須在主執行緒呼叫。
*/
public static void setBlockState(Location loc, BlockState state, int flags) {
net.minecraft.world.level.Level level = ((CraftWorld) loc.getWorld()).getHandle();
BlockPos pos = new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
level.setBlock(pos, state, flags);
}
/** 取得指定 X/Z 位置的地面高度(WORLD_SURFACE 高度圖)。 */
public static int getSurfaceHeight(World world, int x, int z) {
net.minecraft.world.level.Level level = ((CraftWorld) world).getHandle();
BlockPos pos = new BlockPos(x, 0, z);
LevelChunk chunk = level.getChunkAt(pos);
return chunk.getHeight(Heightmap.Types.WORLD_SURFACE, x & 15, z & 15);
}
/** 取得指定 X/Z 位置的動態高度(MOTION_BLOCKING,含水)。 */
public static int getMotionBlockingHeight(World world, int x, int z) {
net.minecraft.world.level.Level level = ((CraftWorld) world).getHandle();
BlockPos pos = new BlockPos(x, 0, z);
LevelChunk chunk = level.getChunkAt(pos);
return chunk.getHeight(Heightmap.Types.MOTION_BLOCKING, x & 15, z & 15);
}
/** 取得 ChunkSection(16 格高的子區段),sectionY 為 section index(非方塊 Y)。 */
public static LevelChunkSection getSection(Chunk chunk, int sectionY) {
LevelChunk nms = getChunk(chunk);
return nms.getSections()[sectionY - nms.getMinSection()];
}
/** 讀取 ChunkSection 中的方塊狀態(localX/Y/Z 為 0-15 相對座標)。 */
public static BlockState getSectionBlockState(
LevelChunkSection section, int localX, int localY, int localZ) {
return section.getBlockState(localX, localY, localZ);
}
/** 取得指定位置的光照等級(SKY 或 BLOCK)。 */
public static int getLightLevel(Location loc, LightLayer layer) {
net.minecraft.world.level.Level level = ((CraftWorld) loc.getWorld()).getHandle();
BlockPos pos = new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
return level.getBrightness(layer, pos);
}
}
BulkBlockEditor.java(批次方塊操作)package com.example.world;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
import java.util.HashMap;
import java.util.Map;
/**
* 批次方塊操作工具。
* 收集所有修改後一次性提交,減少客戶端更新封包數量。
* 必須在主執行緒使用。
*/
@SuppressWarnings("UnstableApiUsage")
public class BulkBlockEditor {
private final net.minecraft.world.level.Level level;
private final Map<BlockPos, BlockState> pending = new HashMap<>();
public BulkBlockEditor(World world) {
this.level = ((CraftWorld) world).getHandle();
}
/** 排隊一個方塊修改。 */
public BulkBlockEditor set(int x, int y, int z, BlockState state) {
pending.put(new BlockPos(x, y, z), state);
return this;
}
/** 排隊填充一個立方體範圍(minX..maxX, minY..maxY, minZ..maxZ)。 */
public BulkBlockEditor fill(int x1, int y1, int z1, int x2, int y2, int z2, BlockState state) {
for (int x = x1; x <= x2; x++)
for (int y = y1; y <= y2; y++)
for (int z = z1; z <= z2; z++)
pending.put(new BlockPos(x, y, z), state);
return this;
}
/**
* 提交所有修改。
* flags=2 只發送封包給客戶端,不觸發鄰居更新(效能最高)。
* flags=3 觸發鄰居更新 + 發送封包(物理效果正確但較慢)。
*/
public void commit(int flags) {
for (Map.Entry<BlockPos, BlockState> entry : pending.entrySet()) {
level.setBlock(entry.getKey(), entry.getValue(), flags);
}
pending.clear();
}
/** 清除所有排隊的修改。 */
public void clear() {
pending.clear();
}
public int pendingCount() {
return pending.size();
}
}
src/main/java/com/example/
├── MyNmsPlugin.java
└── world/
├── ChunkAccessUtil.java
└── BulkBlockEditor.java
BulkBlockEditor.commit() 亦需在主執行緒呼叫getBlockState、getHeight)在不修改世界的前提下可在 async 讀取,但 Paper 不保證一致性Skills/_shared/nms-threading.md| 錯誤 | 原因 | 解法 |
|------|------|------|
| getChunk() 回傳未載入狀態 | 區塊未完全生成 | 呼叫前先 world.loadChunk(cx, cz) 確保載入 |
| ArrayIndexOutOfBoundsException | sectionY 超出範圍 | 確認 sectionY 在 chunk.getMinSection() 至 getMaxSection() 之間 |
| 方塊更新後客戶端無反應 | flags=0 或未呼叫 commit() | 改用 flags=2(SEND_TO_CLIENTS) |
| 大量更新造成伺服器卡頓 | 單 tick 修改過多方塊 | 分批執行(Bukkit scheduler runTaskTimer) |
development
透過 NMS Scoreboard/Objective/Team API 操作 sidebar、tablist 顯示名稱與計分板(Paper NMS + Mojang-mapped)/ Operate sidebar, tablist, and scoreboard via NMS Scoreboard/Objective/Team API
research
操作 GameProfile 進行 skin 注入,用於 NPC 外觀設定與假玩家實體(Paper NMS + Mojang-mapped)/ Manipulate GameProfile for skin injection used in NPC appearance and fake player entities
tools
透過 ClientboundLevelParticlesPacket 實現進階 NMS 粒子效果:客戶端專屬、大量粒子、自定義參數(Paper NMS + Mojang-mapped)/ Advanced NMS particle effects via ClientboundLevelParticlesPacket with per-client and bulk support
documentation
直接操作 CompoundTag 讀寫物品、實體、方塊實體的 NBT 資料(Paper NMS + Mojang-mapped)/ Read and write NBT data on items, entities, and block entities via CompoundTag