@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();
    }
  }
Example #2
0
 @Override
 public Block getBlockAt(Vector3i pos) {
   int index = chunkIndexOf(pos);
   Chunk chunk = chunks[index];
   if (chunk != null) {
     return chunk.getBlock(ChunkMath.calcBlockPos(pos));
   }
   return null;
 }
 private boolean areAdjacentChunksReady(Chunk chunk) {
   Vector3i centerChunkPos = chunk.getPosition();
   for (Side side : Side.values()) {
     Vector3i adjChunkPos = side.getAdjacentPos(centerChunkPos);
     Chunk adjChunk = nearCache.get(adjChunkPos);
     boolean adjChunkReady = (adjChunk != null && adjChunk.isReady());
     if (!adjChunkReady) {
       return false;
     }
   }
   return true;
 }
 private ChunkViewCore createWorldView(Region3i region, Vector3i offset) {
   Chunk[] chunks = new Chunk[region.sizeX() * region.sizeY() * region.sizeZ()];
   for (Vector3i chunkPos : region) {
     Chunk chunk = nearCache.get(chunkPos);
     if (chunk == null || !chunk.isReady()) {
       return null;
     }
     chunkPos.sub(region.minX(), region.minY(), region.minZ());
     int index = TeraMath.calculate3DArrayIndex(chunkPos, region.size());
     chunks[index] = chunk;
   }
   return new ChunkViewCoreImpl(
       chunks, region, offset, blockManager.getBlock(BlockManager.AIR_ID));
 }
  @Override
  public void dispose() {
    shutdown();

    for (Chunk chunk : nearCache.values()) {
      unloadChunkInternal(chunk.getPosition());
      chunk.dispose();
    }
    nearCache.clear();
    /*
     * The chunk monitor needs to clear chunk references, so it's important
     * that no new chunk get created
     */
    ChunkMonitor.fireChunkProviderDisposed(this);
  }
 void gatherBlockPositionsForDeactivate(Chunk chunk) {
   try {
     deactivateBlocksQueue.put(createBatchBlockEventMappings(chunk));
   } catch (InterruptedException e) {
     logger.error("Failed to queue deactivation of blocks for {}", chunk.getPosition());
   }
 }
 private void updateRelevance() {
   for (ChunkRelevanceRegion chunkRelevanceRegion : regions.values()) {
     chunkRelevanceRegion.update();
     if (chunkRelevanceRegion.isDirty()) {
       for (Vector3i pos : chunkRelevanceRegion.getNeededChunks()) {
         Chunk chunk = nearCache.get(pos);
         if (chunk != null && chunk.isReady()) {
           chunkRelevanceRegion.chunkReady(chunk);
         } else if (chunk == null) {
           createOrLoadChunk(pos);
         }
       }
       chunkRelevanceRegion.setUpToDate();
     }
   }
 }
 // Generates all non-temporary block entities
 private void generateBlockEntities(Chunk chunk) {
   ChunkBlockIterator i = chunk.getBlockIterator();
   while (i.next()) {
     if (i.getBlock().isKeepActive()) {
       registry.getBlockEntityAt(i.getBlockPos());
     }
   }
 }
  @Override
  public void deactivateChunk(Chunk chunk) {
    Collection<EntityRef> entitiesOfChunk = getEntitiesOfChunk(chunk);
    ChunkImpl chunkImpl = (ChunkImpl) chunk; // storage manager only works with ChunkImpl
    unloadedAndUnsavedChunkMap.put(
        chunk.getPosition(),
        new CompressedChunkBuilder(getEntityManager(), chunkImpl, entitiesOfChunk, true));

    entitiesOfChunk.forEach(this::deactivateOrDestroyEntityRecursive);
  }
 private void updateAdjacentChunksReadyFieldOfAdjChunks(Chunk chunkInCenter) {
   Vector3i centerChunkPos = chunkInCenter.getPosition();
   for (Side side : Side.values()) {
     Vector3i adjChunkPos = side.getAdjacentPos(centerChunkPos);
     Chunk adjChunk = nearCache.get(adjChunkPos);
     if (adjChunk != null) {
       updateAdjacentChunksReadyFieldOf(adjChunk);
     }
   }
 }
Example #11
0
 private static synchronized ChunkMonitorEntry registerChunk(Chunk chunk) {
   Preconditions.checkNotNull(chunk, "The parameter 'chunk' must not be null");
   final Vector3i pos = chunk.getPosition();
   ChunkMonitorEntry entry = CHUNKS.get(pos);
   if (entry == null) {
     entry = new ChunkMonitorEntry(pos);
     CHUNKS.put(pos, entry);
   }
   entry.addChunk(chunk);
   return entry;
 }
  private TShortObjectMap<TIntList> createBatchBlockEventMappings(Chunk chunk) {
    TShortObjectMap<TIntList> batchBlockMap = new TShortObjectHashMap<>();
    for (Block block : blockManager.listRegisteredBlocks()) {
      if (block.isLifecycleEventsRequired()) {
        batchBlockMap.put(block.getId(), new TIntArrayList());
      }
    }

    ChunkBlockIterator i = chunk.getBlockIterator();
    while (i.next()) {
      if (i.getBlock().isLifecycleEventsRequired()) {
        TIntList positionList = batchBlockMap.get(i.getBlock().getId());
        positionList.add(i.getBlockPos().x);
        positionList.add(i.getBlockPos().y);
        positionList.add(i.getBlockPos().z);
      }
    }
    return batchBlockMap;
  }
  private boolean unloadChunkInternal(Vector3i pos) {
    Chunk chunk = nearCache.get(pos);
    if (chunk.isLocked()) {
      return false;
    }

    chunk.lock();
    try {
      if (!chunk.isReady()) {
        // Chunk hasn't been finished or changed, so just drop it.
        Iterator<ReadyChunkInfo> infoIterator = sortedReadyChunks.iterator();
        while (infoIterator.hasNext()) {
          ReadyChunkInfo next = infoIterator.next();
          if (next.getPos().equals(chunk.getPosition())) {
            infoIterator.remove();
            break;
          }
        }
        return true;
      }
      worldEntity.send(new BeforeChunkUnload(pos));
      for (ChunkRelevanceRegion region : regions.values()) {
        region.chunkUnloaded(pos);
      }
      storageManager.deactivateChunk(chunk);
      chunk.dispose();
      updateAdjacentChunksReadyFieldOfAdjChunks(chunk);

      try {
        unloadRequestTaskMaster.put(new ChunkUnloadRequest(chunk, this));
      } catch (InterruptedException e) {
        logger.error("Failed to enqueue unload request for {}", chunk.getPosition(), e);
      }

      return true;
    } finally {
      chunk.unlock();
    }
  }
 private boolean isChunkReady(Chunk chunk) {
   return chunk != null && chunk.isReady();
 }
  @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();
      }
    }
  }
 private void updateAdjacentChunksReadyFieldOf(Chunk chunk) {
   chunk.setAdjacentChunksReady(areAdjacentChunksReady(chunk));
 }
Example #17
0
 public static void fireChunkRevived(Chunk chunk) {
   Preconditions.checkNotNull(chunk, "The parameter 'chunk' must not be null");
   post(new ChunkMonitorEvent.Revived(chunk.getPosition()));
 }
Example #18
0
 public static void fireChunkDeflated(Chunk chunk, int oldSize, int newSize) {
   Preconditions.checkNotNull(chunk, "The parameter 'chunk' must not be null");
   post(new ChunkMonitorEvent.Deflated(chunk.getPosition(), oldSize, newSize));
 }
  /**
   * Generate the local contents of a chunk. This should be purely deterministic from the chunk
   * contents, chunk position and world seed - should not depend on external state or other data.
   *
   * @param c
   */
  public void generateChunk(Chunk c) {

    int hm_x = (((c.getChunkWorldPosX() / Chunk.SIZE_X) % 512) + 512) % 512;
    int hm_z = (((c.getChunkWorldPosZ() / Chunk.SIZE_Z) % 512) + 512) % 512;

    double scaleFactor = 0.05 * Chunk.SIZE_Y;

    double p00 = heightmap[hm_x][hm_z] * scaleFactor;
    double p10 = heightmap[(hm_x - 1 + 512) % 512][(hm_z) % 512] * scaleFactor;
    double p11 = heightmap[(hm_x - 1 + 512) % 512][(hm_z + 1 + 512) % 512] * scaleFactor;
    double p01 = heightmap[(hm_x) % 512][(hm_z + 1 + 512) % 512] * scaleFactor;

    for (int x = 0; x < Chunk.SIZE_X; x++) {
      for (int z = 0; z < Chunk.SIZE_Z; z++) {
        WorldBiomeProvider.Biome type =
            biomeProvider.getBiomeAt(c.getBlockWorldPosX(x), c.getBlockWorldPosZ(z));

        // calculate avg height
        double interpolatedHeight =
            lerp(
                x / (double) Chunk.SIZE_X,
                lerp(z / (double) Chunk.SIZE_Z, p10, p11),
                lerp(z / (double) Chunk.SIZE_Z, p00, p01));

        // Scale the height to fit one chunk (suppose we have max height 20 on the Heigthmap
        // ToDo: Change this formula in later implementation of vertical chunks
        double threshold = Math.floor(interpolatedHeight);

        for (int y = Chunk.SIZE_Y - 1; y >= 0; y--) {
          if (y == 0) { // The very deepest layer of the world is an
            // indestructible mantle
            c.setBlock(x, y, z, mantle);
            break;
          } else if (y < threshold) {
            c.setBlock(x, y, z, stone);
          } else if (y == threshold) {
            if (y < Chunk.SIZE_Y * 0.05 + 1) {
              c.setBlock(x, y, z, sand);
            } else if (y < Chunk.SIZE_Y * 0.05 * 12) {
              c.setBlock(x, y, z, grass);
            } else {
              c.setBlock(x, y, z, snow);
            }
          } else {
            if (y <= Chunk.SIZE_Y / 20) { // Ocean
              c.setBlock(x, y, z, water);
              c.setLiquid(x, y, z, new LiquidData(LiquidType.WATER, Chunk.MAX_LIQUID_DEPTH));

            } else {
              c.setBlock(x, y, z, air);
            }
          }
        }
      }
    }
  }