@Override public Block getBlock(int x, int y, int z) { Vector3i pos = new Vector3i(x, y, z); Block block = blocks.get(pos); if (block != null) { return block; } // TODO block & biome manager Vector3i chunkPos = ChunkMath.calcChunkPos(pos); Chunk chunk = chunks.get(chunkPos); if (chunk == null && worldGenerator != null) { chunk = new ChunkImpl(chunkPos, blockManager, biomeManager, extraDataManager); worldGenerator.createChunk(chunk, entityBuffer); chunks.put(chunkPos, chunk); } if (chunk != null) { return chunk.getBlock(ChunkMath.calcBlockPos(pos.x, pos.y, pos.z)); } return null; }
@Override public Vector3i chunkToWorldPosition(BaseVector3i blockPos) { return chunkToWorldPosition(blockPos.x(), blockPos.y(), blockPos.z()); }
@Override public Vector3i chunkToWorldPosition(int x, int y, int z) { return new Vector3i(chunkToWorldPositionX(x), chunkToWorldPositionY(y), chunkToWorldPositionZ(z)); }
public synchronized byte[] buildEncodedChunk() { if (result == null) { EntityData.ChunkStore.Builder encoded; if (viaSnapshot) { encoded = chunk.encodeAndReleaseSnapshot(); } else { encoded = chunk.encode(); } encoded.setStore(entityStore); EntityData.ChunkStore store = encoded.build(); result = compressChunkStore(store); } return result; }
@Override public void dispose() { disposed = true; ready = false; disposeMesh(); /* * Explicitly do not clear data, so that background threads that work with the chunk can finish. */ ChunkMonitor.fireChunkDisposed(this); }
/** * * @param entitiesToSave all persistent entities within the given chunk * @param chunkUnloaded if true the chunk data will be used directly. If deactivate is false then the chunk will be * but in snapshot mode so that concurrent modifications (and possibly future unload) is * possible. */ public CompressedChunkBuilder(EngineEntityManager entityManager, ChunkImpl chunk, Collection<EntityRef> entitiesToSave, boolean chunkUnloaded) { EntityStorer storer = new EntityStorer(entityManager); entitiesToSave.stream().filter(EntityRef::isPersistent).forEach(storer::store); storedEntities = storer.getStoredEntities(); this.entityStore = storer.finaliseStore(); this.chunk = chunk; this.viaSnapshot = !chunkUnloaded; if (viaSnapshot) { this.chunk.createSnapshot(); } }
private Chunk createChunk(int x, int y, int z) { return new ChunkImpl(new Vector3i(x, y, z), blockManager, biomeManager, extraDataManager); } }
public static Chunk decode(EntityData.ChunkStore message, BlockManager blockManager, BiomeManager biomeManager, ExtraBlockDataManager extraDataManager) { Preconditions.checkNotNull(message, "The parameter 'message' must not be null"); if (!message.hasX() || !message.hasY() || !message.hasZ()) { throw new IllegalArgumentException("Ill-formed protobuf message. Missing chunk position."); } Vector3i pos = new Vector3i(message.getX(), message.getY(), message.getZ()); if (!message.hasBlockData()) { throw new IllegalArgumentException("Ill-formed protobuf message. Missing block data."); } final TeraArray blockData = runLengthDecode(message.getBlockData()); final TeraArray biomeData = runLengthDecode(message.getBiomeData()); final TeraArray[] extraData = extraDataManager.makeDataArrays(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z); for (int i = 0; i < extraData.length; i++) { runLengthDecode(message.getExtraData(i), extraData[i]); } return new ChunkImpl(pos, blockData, biomeData, extraData, blockManager, biomeManager); }
@Override public void run() { ChunkStore chunkStore = storageManager.loadChunkStore(getPosition()); Chunk chunk; EntityBufferImpl buffer = new EntityBufferImpl(); if (chunkStore == null) { chunk = new ChunkImpl(getPosition(), blockManager, biomeManager, extraDataManager); generator.createChunk(chunk, buffer); } else { chunk = chunkStore.getChunk(); } InternalLightProcessor.generateInternalLighting(chunk); chunk.deflate(); TShortObjectMap<TIntList> mappings = createBatchBlockEventMappings(chunk); readyChunks.offer(new ReadyChunkInfo(chunk, mappings, chunkStore, buffer.getAll())); } });
@Test public void testUnblockedSunlightRegenPropagation() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, biomeManager, extraDataManager); InternalLightProcessor.generateInternalLighting(chunk); for (Vector3i pos : Region3i.createFromMinAndSize(Vector3i.zero(), new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y, ChunkConstants.SIZE_Z))) { byte expectedRegen = (byte) Math.min(ChunkConstants.SIZE_Y - pos.y - 1, ChunkConstants.MAX_SUNLIGHT_REGEN); assertEquals(expectedRegen, chunk.getSunlightRegen(pos)); } }
@Test public void testUnblockedSunlightPropagation() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, biomeManager, extraDataManager); InternalLightProcessor.generateInternalLighting(chunk); for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 15, ChunkConstants.SIZE_Z))) { assertEquals("Incorrect lighting at " + pos, 15 - pos.y, chunk.getSunlight(pos)); } }
@Test public void testStoreAndRestoreChunkStore() { Chunk chunk = new ChunkImpl(CHUNK_POS, blockManager, biomeManager, extraDataManager); chunk.setBlock(0, 0, 0, testBlock); chunk.markReady(); ChunkProvider chunkProvider = mock(ChunkProvider.class); when(chunkProvider.getAllChunks()).thenReturn(Arrays.asList(chunk)); CoreRegistry.put(ChunkProvider.class, chunkProvider); esm.waitForCompletionOfPreviousSaveAndStartSaving(); esm.finishSavingAndShutdown(); ChunkStore restored = esm.loadChunkStore(CHUNK_POS); assertNotNull(restored); assertEquals(CHUNK_POS, restored.getChunkPosition()); assertNotNull(restored.getChunk()); assertEquals(testBlock, restored.getChunk().getBlock(0, 0, 0)); }
@Test public void testBlockedAtTopSunlightRegenPropagationResets() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, biomeManager, extraDataManager); for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 63, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { chunk.setBlock(pos, solidBlock); } InternalLightProcessor.generateInternalLighting(chunk); for (Vector3i pos : Region3i.createFromMinAndSize(Vector3i.zero(), new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y - 1, ChunkConstants.SIZE_Z))) { byte expectedRegen = (byte) Math.min(ChunkConstants.SIZE_Y - pos.y - 2, ChunkConstants.MAX_SUNLIGHT_REGEN); assertEquals(expectedRegen, chunk.getSunlightRegen(pos)); } }
@Test public void testUnblockedSunlightPropagationAfterHittingMaxRegen() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, biomeManager, extraDataManager); InternalLightProcessor.generateInternalLighting(chunk); for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 15, 0), new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y - 15, ChunkConstants.SIZE_Z))) { assertEquals(0, chunk.getSunlight(pos)); } for (Vector3i pos : Region3i.createFromMinAndSize(Vector3i.zero(), new Vector3i(ChunkConstants.SIZE_X, ChunkConstants.SIZE_Y - ChunkConstants.MAX_SUNLIGHT_REGEN, ChunkConstants.SIZE_Z))) { byte expectedSunlight = (byte) Math.min(ChunkConstants.SIZE_Y - ChunkConstants.SUNLIGHT_REGEN_THRESHOLD - pos.y - 1, ChunkConstants.MAX_SUNLIGHT); assertEquals("Incorrect lighting at " + pos, expectedSunlight, chunk.getSunlight(pos)); } }
@Test public void testChunkSurvivesStorageSaveAndRestore() throws Exception { Chunk chunk = new ChunkImpl(CHUNK_POS, blockManager, biomeManager, extraDataManager); chunk.setBlock(0, 0, 0, testBlock); chunk.setBlock(0, 4, 2, testBlock2); chunk.markReady(); ChunkProvider chunkProvider = mock(ChunkProvider.class); when(chunkProvider.getAllChunks()).thenReturn(Arrays.asList(chunk)); when(chunkProvider.getChunk(Matchers.any(Vector3i.class))).thenReturn(chunk); CoreRegistry.put(ChunkProvider.class, chunkProvider); boolean storeChunkInZips = true; esm.setStoreChunksInZips(storeChunkInZips); esm.waitForCompletionOfPreviousSaveAndStartSaving(); esm.finishSavingAndShutdown(); EntitySystemSetupUtil.addReflectionBasedLibraries(context); EntitySystemSetupUtil.addEntityManagementRelatedClasses(context); EngineEntityManager newEntityManager = context.get(EngineEntityManager.class); StorageManager newSM = new ReadWriteStorageManager(savePath, moduleEnvironment, newEntityManager, blockManager, biomeManager, extraDataManager, storeChunkInZips, recordAndReplaySerializer, recordAndReplayUtils, recordAndReplayCurrentStatus); newSM.loadGlobalStore(); ChunkStore restored = newSM.loadChunkStore(CHUNK_POS); assertNotNull(restored); assertEquals(CHUNK_POS, restored.getChunkPosition()); assertNotNull(restored.getChunk()); assertEquals(testBlock, restored.getChunk().getBlock(0, 0, 0)); assertEquals(testBlock2, restored.getChunk().getBlock(0, 4, 2)); }
@Test public void testBetweenChunksSimpleSunlightRegenOnly() { Chunk topChunk = new ChunkImpl(new Vector3i(0, 1, 0), blockManager, biomeManager, extraDataManager); Chunk bottomChunk = new ChunkImpl(new Vector3i(0, 0, 0), blockManager, biomeManager, extraDataManager); provider.addChunk(topChunk); provider.addChunk(bottomChunk); for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { topChunk.setSunlight(pos, ChunkConstants.MAX_SUNLIGHT); topChunk.setSunlightRegen(pos, ChunkConstants.MAX_SUNLIGHT_REGEN); } InternalLightProcessor.generateInternalLighting(bottomChunk); propagator.propagateBetween(topChunk, bottomChunk, Side.BOTTOM, true); propagator.process(); for (Vector3i pos : ChunkConstants.CHUNK_REGION) { assertEquals("Incorrect at position " + pos, ChunkConstants.MAX_SUNLIGHT_REGEN, bottomChunk.getSunlightRegen(pos)); } }
@Test public void testBlockedSunlightPropagation() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, biomeManager, extraDataManager); for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 4, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { chunk.setBlock(pos, solidBlock); } InternalLightProcessor.generateInternalLighting(chunk); for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 5, ChunkConstants.SIZE_Z))) { assertEquals("Incorrect lighting at " + pos, 0, chunk.getSunlight(pos)); } }
@Test public void testBetweenChunksSimple() { Chunk topChunk = new ChunkImpl(new Vector3i(0, 1, 0), blockManager, biomeManager, extraDataManager); Chunk bottomChunk = new ChunkImpl(new Vector3i(0, 0, 0), blockManager, biomeManager, extraDataManager); provider.addChunk(topChunk); provider.addChunk(bottomChunk); for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { topChunk.setSunlight(pos, ChunkConstants.MAX_SUNLIGHT); topChunk.setSunlightRegen(pos, ChunkConstants.MAX_SUNLIGHT_REGEN); } InternalLightProcessor.generateInternalLighting(bottomChunk); propagator.propagateBetween(topChunk, bottomChunk, Side.BOTTOM, true); propagator.process(); sunlightPropagator.process(); for (Vector3i pos : ChunkConstants.CHUNK_REGION) { assertEquals("Incorrect at position " + pos, ChunkConstants.MAX_SUNLIGHT, bottomChunk.getSunlight(pos)); assertEquals("Incorrect at position " + pos, ChunkConstants.MAX_SUNLIGHT_REGEN, bottomChunk.getSunlightRegen(pos)); } }
@Test public void testBlockedSunlightRegenPropagationResets() { Chunk chunk = new ChunkImpl(0, 0, 0, blockManager, biomeManager, extraDataManager); for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 60, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { chunk.setBlock(pos, solidBlock); } InternalLightProcessor.generateInternalLighting(chunk); for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 61, 0), new Vector3i(ChunkConstants.SIZE_X, 3, ChunkConstants.SIZE_Z))) { byte expectedRegen = (byte) Math.min(ChunkConstants.SIZE_Y - pos.y - 1, ChunkConstants.MAX_SUNLIGHT_REGEN); assertEquals(expectedRegen, chunk.getSunlightRegen(pos)); } for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 60, 0), new Vector3i(ChunkConstants.SIZE_X, 1, ChunkConstants.SIZE_Z))) { assertEquals(0, chunk.getSunlightRegen(pos)); } for (Vector3i pos : Region3i.createFromMinAndSize(new Vector3i(0, 0, 0), new Vector3i(ChunkConstants.SIZE_X, 59, ChunkConstants.SIZE_Z))) { byte expectedRegen = (byte) Math.min(60 - pos.y - 1, ChunkConstants.MAX_SUNLIGHT_REGEN); assertEquals(expectedRegen, chunk.getSunlightRegen(pos)); } }
@Test public void testEntitySurvivesStorageInChunkStore() throws Exception { Chunk chunk = new ChunkImpl(CHUNK_POS, blockManager, biomeManager, extraDataManager); chunk.setBlock(0, 0, 0, testBlock); chunk.markReady();