方塊快速下落

方塊快速下落 - Instant Falling(IF)

方塊快速下落(Instant Falling - IF)

minecraft 為了在區塊裝飾時預先處理沙子等下落方塊,故添加了本規則。(後續文章可能會使用 IF 來代指它 [瞬時下落 Instant Falling])

BlockFalling.java
public class BlockFalling extends Block {
  public static boolean fallInstantly; 
  private void checkFallable(World worldIn, BlockPos pos) {
    if (canFallThrough(worldIn.getBlockState(pos.down())) && pos.getY() >= 0) {
      int i = 32;
      if (!fallInstantly && worldIn.isAreaLoaded(pos.add(-32, -32, -32), pos.add(32, 32, 32))) {
        if (!worldIn.isRemote) {
          EntityFallingBlock entityfallingblock = new EntityFallingBlock(worldIn, (double) pos.getX() + 0.5D,
              (double) pos.getY(), (double) pos.getZ() + 0.5D, worldIn.getBlockState(pos));
          this.onStartFalling(entityfallingblock);
          worldIn.spawnEntity(entityfallingblock);
        }
      } else {
        worldIn.setBlockToAir(pos); // 設定當前位置為空氣
        BlockPos blockpos;
        for (blockpos = pos.down(); canFallThrough(worldIn.getBlockState(blockpos)) // 判斷下方是否能下落            && blockpos.getY() > 0; blockpos = blockpos.down()) { // 若不能,則繼續往下找          ;
        }

        if (blockpos.getY() > 0) {
          worldIn.setBlockState(blockpos.up(), this.getDefaultState()); // 設定上方為目前的方塊(注意這邊是使用 `getDefaultState()`)        }
      }
    }
  }
}

在哪被修改

會在在區塊裝飾時短暫開啟該 flag,並在結束後關閉。

小知識下面的 code 上面有比較完整的~~

ChunkGeneratorOverworld.java
public void populate(int x, int z) {
  BlockFalling.fallInstantly = true;   // 一些裝飾邏輯
  BlockFalling.fallInstantly = false; }

如何開啟

在裝飾時也會開啟 IF,所以開法和 ITT 一樣。 ITT 開法

如何關閉

  1. 重啟服務器
  2. 重新加載之前未被加載過的區塊 (裝飾),注意這邊是任意緯度都可以(若要保留 ITT 請在另一個緯度加載)

開啟時影響

開啟後由於有關於 BlockFalling 採用的是 worldIn.setBlockState(blockpos.up(), this.getDefaultState());,方塊狀態會被重置成預設狀態,得任何基於狀態保存的方塊,都會變成預設值,例如:

  1. 紅沙 -> 一般沙子
  2. 壞掉的鐵砧 -> 沒壞的鐵砧
  3. 各色混泥土粉末 -> 白色混泥土粉末

龍蛋

龍蛋並非使用 BlockFalling 處理,而是有自己的邏輯:

BlockDragonEgg.java
public class BlockDragonEgg extends Block {
  // ...

  private void checkFall(World worldIn, BlockPos pos) {
    if (BlockFalling.canFallThrough(worldIn.getBlockState(pos.down())) && pos.getY() >= 0) { // 設定當前位置為空氣      int i = 32;

      if (!BlockFalling.fallInstantly && worldIn.isAreaLoaded(pos.add(-32, -32, -32), pos.add(32, 32, 32))) {
        worldIn.spawnEntity(new EntityFallingBlock(worldIn, (double) ((float) pos.getX() + 0.5F), (double) pos.getY(),
            (double) ((float) pos.getZ() + 0.5F), this.getDefaultState()));
      } else {
        worldIn.setBlockToAir(pos);
        BlockPos blockpos;
        for (blockpos = pos; BlockFalling.canFallThrough(worldIn.getBlockState(blockpos)) // 判斷下方是否能下落            && blockpos.getY() > 0; blockpos = blockpos.down()) { // 若不能,則繼續往下找          ;
        }

        if (blockpos.getY() > 0) {
          worldIn.setBlockState(blockpos, this.getDefaultState(), 2); // 設定上方為目前的方塊(注意這邊是使用 `getDefaultState()`)        }
      }
    }
  }
}

由於代碼中有 bug worldIn.setBlockState(blockpos, this.getDefaultState(), 2);,並沒有使用 blockpos.up(),導致比預期少一低一格,所以龍蛋會覆蓋原本的方塊。
得在 IF 開啟時,下落的龍蛋能夠破獲各種方塊(包括但不限於基岩等)

原版基於龍蛋弱加載破基岩也是基於這個 bug(由於上面的 worldIn.isAreaLoaded(pos.add(-32, -32, -32), pos.add(32, 32, 32)) 為 false, 龍蛋使用和 fallInstantly 一樣的邏輯)

注意事項

似乎沒有 ?!