調色板

介紹 Minecraft 1.12.2 子區塊內的調色板系統,解釋 BlockState 與 bits 映射的原理與程式實作

調色板 (palette)

在 1.12.2 中,minecraft chunk 中又在細分 16 個子區塊 (sub-chunk),每個子區塊有 16 個方塊層 (block layer),每個方塊層有 16x16x16(4096) 的方塊。

而調色板的功能,就是一個將方塊狀態映射到數字的一種東西,他使的子區塊的方塊狀態能夠按照一定的順序排列成一個數字陣列,從而保存,對於包含不同狀態數量的紫區塊,遊戲會選擇使用不同的調色板類型來儲存方塊狀態。

Chunk.java
public class Chunk {
  private final ExtendedBlockStorage[] storageArrays;

  public Chunk(World worldIn, int x, int z) {
    this.storageArrays = new ExtendedBlockStorage[16]; // 16 個子區塊

    // ...
  }

  // ...
}
方塊狀態數bits調色板類型備註
1~164線性調色板 (BlockStatePaletteLinear)bits <= 4 強制固定 4 bits,不會用 1,2,3 bits
17~325哈希調色板 (BlockStatePaletteHashMap)使用 HashMap,查找成本略高於線性,但支援動態擴充。狀態數落在此區間時分配 5 bits。
33~646哈希調色板 (BlockStatePaletteHashMap)同上,當狀態數超過 32 會自動升級至 6 bits
65~1287哈希調色板 (BlockStatePaletteHashMap)同上,當狀態數超過 64 會自動升級至 7 bits
129~2568哈希調色板 (BlockStatePaletteHashMap)HashMap 的上限,最多支援 256 種狀態,對應 8 bits 編碼
>= 2579+註冊表調色板 (REGISTRY_BASED_PALETTE)直接用全域 Block.BLOCK_STATE_IDS,bits 會依實際註冊數量計算 (預設 HashTableSize 為 512 ())
BlockStateContainer.java
public class BlockStateContainer implements IBlockStatePaletteResizer {   public BlockStateContainer() {
    this.setBits(4);   }

  private void setBits(int bitsIn) {
    if (bitsIn != this.bits) {
      this.bits = bitsIn;

      if (this.bits <= 4) {         this.bits = 4;         this.palette = new BlockStatePaletteLinear(this.bits, this);       } else if (this.bits <= 8) {         this.palette = new BlockStatePaletteHashMap(this.bits, this);       } else {         this.palette = REGISTRY_BASED_PALETTE;         this.bits = MathHelper.log2DeBruijn(Block.BLOCK_STATE_IDS.size());       } 
      this.palette.idFor(AIR_BLOCK_STATE);
      this.storage = new BitArray(this.bits, 4096);
    }
  }

  // ...
} 

線性調色板 (BlockStatePaletteLinear)

BlockStatePaletteLinear.java
public class BlockStatePaletteLinear implements IBlockStatePalette {   private final IBlockState[] states;
  private final IBlockStatePaletteResizer resizeHandler;
  private final int bits;
  private int arraySize;

  public BlockStatePaletteLinear(int bitsIn, IBlockStatePaletteResizer resizeHandlerIn) {
    this.states = new IBlockState[1 << bitsIn]; // bitsIn 傳入的是 4,即 16 個狀態    this.bits = bitsIn;
    this.resizeHandler = resizeHandlerIn;
  }

  // ...
} 

哈希調色板 (BlockStatePaletteHashMap)

BlockStatePaletteHashMap.java
public class BlockStatePaletteHashMap implements IBlockStatePalette {   private final IntIdentityHashBiMap<IBlockState> statePaletteMap;
  private final IBlockStatePaletteResizer paletteResizer;
  private final int bits;

  public BlockStatePaletteHashMap(int bitsIn, IBlockStatePaletteResizer paletteResizerIn) {
    this.bits = bitsIn;
    this.paletteResizer = paletteResizerIn;
    this.statePaletteMap = new IntIdentityHashBiMap<IBlockState>(1 << bitsIn); // bitsIn 傳入的是 5~8,即 17~256 個狀態  }
} 

註冊表調色板 (REGISTRY_BASED_PALETTE)

Block.java
ObjectIntIdentityMap.java
public class Block implements IBlock {   public static final ObjectIntIdentityMap<IBlockState> BLOCK_STATE_IDS = new ObjectIntIdentityMap<IBlockState>(); 
  // ...
}