private void processBlockChanges(NetData.NetMessage message) {
   for (NetData.BlockChangeMessage blockChange : message.getBlockChangeList()) {
     Block newBlock = blockManager.getBlock((short) blockChange.getNewBlock());
     logger.debug("Received block change to {}", newBlock);
     // TODO: Store changes to blocks that aren't ready to be modified (the surrounding chunks
     // aren't available)
     WorldProvider worldProvider = CoreRegistry.get(WorldProvider.class);
     Vector3i pos = NetMessageUtil.convert(blockChange.getPos());
     if (worldProvider.isBlockRelevant(pos)) {
       worldProvider.setBlock(pos, newBlock);
     } else {
       awaitingChunkReadyBlockUpdates.put(ChunkMath.calcChunkPos(pos), blockChange);
     }
   }
 }
  @Override
  public void onChunkReady(Vector3i chunkPos) {
    WorldProvider worldProvider = CoreRegistry.get(WorldProvider.class);

    List<NetData.BlockChangeMessage> updateBlockMessages =
        awaitingChunkReadyBlockUpdates.removeAll(chunkPos);
    for (NetData.BlockChangeMessage message : updateBlockMessages) {
      Vector3i pos = NetMessageUtil.convert(message.getPos());
      Block newBlock = blockManager.getBlock((short) message.getNewBlock());
      worldProvider.setBlock(pos, newBlock);
    }

    List<NetData.BiomeChangeMessage> updateBiomeMessages =
        awaitingChunkReadyBiomeUpdates.removeAll(chunkPos);
    for (NetData.BiomeChangeMessage message : updateBiomeMessages) {
      Vector3i pos = NetMessageUtil.convert(message.getPos());
      Biome newBiome = biomeManager.getBiomeByShortId((short) message.getNewBiome());
      worldProvider.setBiome(pos, newBiome);
    }
  }