@Override
  public void purgeWorld() {
    ChunkMonitor.fireChunkProviderDisposed(this);
    pipeline.shutdown();
    unloadRequestTaskMaster.shutdown(new ChunkUnloadRequest(), true);
    lightMerger.shutdown();

    for (Chunk chunk : nearCache.values()) {
      if (chunk.isReady()) {
        worldEntity.send(new BeforeChunkUnload(chunk.getPosition()));
        storageManager.deactivateChunk(chunk);
        chunk.dispose();
      }
    }
    nearCache.clear();
    readyChunks.clear();
    sortedReadyChunks.clear();
    storageManager.deleteWorld();
    preparingChunks.clear();
    worldEntity.send(new PurgeWorldEvent());

    pipeline = new ChunkGenerationPipeline(new ChunkTaskRelevanceComparator());
    unloadRequestTaskMaster = TaskMaster.createFIFOTaskMaster("Chunk-Unloader", 8);
    lightMerger = new LightMerger<>(this);
    lightMerger.restart();
    ChunkMonitor.fireChunkProviderInitialized(this);

    for (ChunkRelevanceRegion chunkRelevanceRegion : regions.values()) {
      for (Vector3i pos : chunkRelevanceRegion.getCurrentRegion()) {
        createOrLoadChunk(pos);
      }
      chunkRelevanceRegion.setUpToDate();
    }
  }
 private boolean makeChunkAvailable(final ReadyChunkInfo readyChunkInfo) {
   final Chunk chunk = nearCache.get(readyChunkInfo.getPos());
   if (chunk == null) {
     return false;
   }
   for (Vector3i pos : Region3i.createFromCenterExtents(readyChunkInfo.getPos(), 1)) {
     if (nearCache.get(pos) == null) {
       return false;
     }
   }
   lightMerger.beginMerge(chunk, readyChunkInfo);
   return true;
 }
 @Override
 public void shutdown() {
   pipeline.shutdown();
   unloadRequestTaskMaster.shutdown(new ChunkUnloadRequest(), true);
   lightMerger.shutdown();
 }
 public void restart() {
   pipeline.restart();
   unloadRequestTaskMaster.restart();
   lightMerger.restart();
 }
  @Override
  public void completeUpdate() {
    ReadyChunkInfo readyChunkInfo = lightMerger.completeMerge();
    if (readyChunkInfo != null) {
      Chunk chunk = readyChunkInfo.getChunk();
      chunk.lock();
      try {
        chunk.markReady();
        updateAdjacentChunksReadyFieldOf(chunk);
        updateAdjacentChunksReadyFieldOfAdjChunks(chunk);

        if (!readyChunkInfo.isNewChunk()) {
          PerformanceMonitor.startActivity("Generating Block Entities");
          generateBlockEntities(chunk);
          PerformanceMonitor.endActivity();
        }
        if (readyChunkInfo.getChunkStore() != null) {
          readyChunkInfo.getChunkStore().restoreEntities();
        }

        if (!readyChunkInfo.isNewChunk()) {
          PerformanceMonitor.startActivity("Sending OnAddedBlocks");
          readyChunkInfo
              .getBlockPositionMapppings()
              .forEachEntry(
                  new TShortObjectProcedure<TIntList>() {
                    @Override
                    public boolean execute(short id, TIntList positions) {
                      if (positions.size() > 0) {
                        blockManager
                            .getBlock(id)
                            .getEntity()
                            .send(new OnAddedBlocks(positions, registry));
                      }
                      return true;
                    }
                  });
          PerformanceMonitor.endActivity();
        }

        PerformanceMonitor.startActivity("Sending OnActivateBlocks");
        readyChunkInfo
            .getBlockPositionMapppings()
            .forEachEntry(
                new TShortObjectProcedure<TIntList>() {
                  @Override
                  public boolean execute(short id, TIntList positions) {
                    if (positions.size() > 0) {
                      blockManager
                          .getBlock(id)
                          .getEntity()
                          .send(new OnActivatedBlocks(positions, registry));
                    }
                    return true;
                  }
                });
        PerformanceMonitor.endActivity();

        if (!readyChunkInfo.isNewChunk()) {
          worldEntity.send(new OnChunkGenerated(readyChunkInfo.getPos()));
        }
        worldEntity.send(new OnChunkLoaded(readyChunkInfo.getPos()));
        for (ChunkRelevanceRegion region : regions.values()) {
          region.chunkReady(chunk);
        }
      } finally {
        chunk.unlock();
      }
    }
  }