use of org.valkyrienskies.mod.common.ships.block_relocation.SpatialDetector in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.
the class WorldServerShipManager method spawnNewShips.
private void spawnNewShips() {
for (final ImmutableTriple<BlockPos, ShipData, BlockFinder.BlockFinderType> spawnData : spawnQueue) {
final BlockPos physicsInfuserPos = spawnData.getLeft();
final ShipData toSpawn = spawnData.getMiddle();
final BlockFinder.BlockFinderType blockBlockFinderType = spawnData.getRight();
if (loadedShips.containsKey(toSpawn.getUuid())) {
throw new IllegalStateException("Tried spawning a ShipData that was already loaded?\n" + toSpawn);
}
final SpatialDetector detector = BlockFinder.getBlockFinderFor(blockBlockFinderType, physicsInfuserPos, world, VSConfig.maxDetectedShipSize + 1, true);
if (VSConfig.showAnnoyingDebugOutput) {
System.out.println("Attempting to spawn " + toSpawn + " on the thread " + Thread.currentThread().getName());
}
if (detector.foundSet.size() > VSConfig.maxDetectedShipSize || detector.cleanHouse) {
System.err.println("Ship too big or bedrock detected!");
// Skip ship construction
continue;
}
// Fill the chunk claims
int radius = 7;
// TEMP CODE
// Eventually want to create mechanisms that control how many chunks are allocated to a ship
// But for now, lets just give them a bunch of chunks.
ChunkPos centerPos = toSpawn.getChunkClaim().getCenterPos();
for (int chunkX = -radius; chunkX <= radius; chunkX++) {
for (int chunkZ = -radius; chunkZ <= radius; chunkZ++) {
toSpawn.getChunkClaim().addChunkClaim(centerPos.x + chunkX, centerPos.z + chunkZ);
}
}
// When copying the ship chunks we want to keep track of the inertia and center of mass.
IPhysicsObjectCenterOfMassProvider centerOfMassProvider = new BasicCenterOfMassProvider();
// Then create the ship chunks
MutableBlockPos srcLocationPos = new MutableBlockPos();
BlockPos centerDifference = toSpawn.getChunkClaim().getRegionCenter().subtract(physicsInfuserPos);
MutableBlockPos pasteLocationPos = new MutableBlockPos();
Map<Long, Chunk> copiedChunksMap = new HashMap<>();
// First, copy the blocks and tiles to the new chunks
TIntIterator blocksIterator = detector.foundSet.iterator();
while (blocksIterator.hasNext()) {
int hashedPos = blocksIterator.next();
SpatialDetector.setPosWithRespectTo(hashedPos, detector.firstBlock, srcLocationPos);
// Get the BlockPos from the hashedPos
pasteLocationPos.setPos(srcLocationPos.getX() + centerDifference.getX(), srcLocationPos.getY() + centerDifference.getY(), srcLocationPos.getZ() + centerDifference.getZ());
// Then add it to the ShipData block positions set
toSpawn.blockPositions.add(pasteLocationPos.getX(), pasteLocationPos.getY(), pasteLocationPos.getZ());
// Then create a chunk to accommodate this block (if one does not already exist).
int newChunkX = pasteLocationPos.getX() >> 4;
int newChunkZ = pasteLocationPos.getZ() >> 4;
long newChunkPosLong = ChunkPos.asLong(newChunkX, newChunkZ);
if (!copiedChunksMap.containsKey(newChunkPosLong)) {
Chunk chunk = new Chunk(world, newChunkX, newChunkZ);
copiedChunksMap.put(newChunkPosLong, chunk);
}
// Then copy the IBlockState & TileEntity to the new Chunk
// Get the old world Chunk
Chunk chunkToSet = world.getChunk(srcLocationPos);
// Get the new Chunk
Chunk newChunk = copiedChunksMap.get(newChunkPosLong);
// Then get the old IBlockState, as efficiently as possible
int storageIndex = srcLocationPos.getY() >> 4;
// Check that we're placing the block in a valid position
if (storageIndex < 0 || storageIndex >= chunkToSet.storageArrays.length) {
// Invalid position, abort!
throw new IllegalStateException("Incorrect block copy!\n" + srcLocationPos);
}
IBlockState srcState = chunkToSet.storageArrays[storageIndex].get(srcLocationPos.getX() & 15, srcLocationPos.getY() & 15, srcLocationPos.getZ() & 15);
// Then paste that IBlockState into the new ship chunk
int newChunkStorageIndex = pasteLocationPos.getY() >> 4;
if (newChunk.storageArrays[newChunkStorageIndex] == Chunk.NULL_BLOCK_STORAGE) {
newChunk.storageArrays[newChunkStorageIndex] = new ExtendedBlockStorage(newChunkStorageIndex << 4, true);
}
newChunk.storageArrays[newChunkStorageIndex].set(pasteLocationPos.getX() & 15, pasteLocationPos.getY() & 15, pasteLocationPos.getZ() & 15, srcState);
// If this block is force block, then add it to the activeForcePositions list of the ship.
if (BlockPhysicsDetails.isBlockProvidingForce(srcState)) {
toSpawn.activeForcePositions.add(pasteLocationPos);
}
// Also update the center of mass and inertia provider
centerOfMassProvider.onSetBlockState(toSpawn.getInertiaData(), pasteLocationPos, Blocks.AIR.getDefaultState(), srcState);
// Then copy the TileEntity (if there is one)
TileEntity srcTile = world.getTileEntity(srcLocationPos);
if (srcTile != null) {
TileEntity pasteTile;
if (srcTile instanceof IRelocationAwareTile) {
pasteTile = ((IRelocationAwareTile) srcTile).createRelocatedTile(pasteLocationPos, toSpawn);
} else {
NBTTagCompound tileEntNBT = srcTile.writeToNBT(new NBTTagCompound());
// Change the block position to be inside of the Ship
tileEntNBT.setInteger("x", pasteLocationPos.getX());
tileEntNBT.setInteger("y", pasteLocationPos.getY());
tileEntNBT.setInteger("z", pasteLocationPos.getZ());
pasteTile = TileEntity.create(world, tileEntNBT);
}
// Finally, add the new TileEntity to the new ship chunk.
newChunk.addTileEntity(pasteTile);
}
}
for (final Chunk chunk : copiedChunksMap.values()) {
chunk.generateSkylightMap();
}
// Then delete the copied blocks from the old chunks
blocksIterator = detector.foundSet.iterator();
while (blocksIterator.hasNext()) {
int hashedPos = blocksIterator.next();
SpatialDetector.setPosWithRespectTo(hashedPos, detector.firstBlock, srcLocationPos);
Chunk chunkToSet = world.getChunk(srcLocationPos);
// Then get the old IBlockState, as efficiently as possible
int storageIndex = srcLocationPos.getY() >> 4;
// Check that we're placing the block in a valid position
if (storageIndex < 0 || storageIndex >= chunkToSet.storageArrays.length) {
// Invalid position, abort!
throw new IllegalStateException("Incorrect block copy!\n" + srcLocationPos);
}
IBlockState srcState = chunkToSet.storageArrays[storageIndex].get(srcLocationPos.getX() & 15, srcLocationPos.getY() & 15, srcLocationPos.getZ() & 15);
// THIS IS TEMP because its extremely inefficient.
// Come up with a clever way to let clients figure this out in the future.
world.notifyBlockUpdate(srcLocationPos, srcState, Blocks.AIR.getDefaultState(), 3);
// Finally, delete the old IBlockState and TileEntity from the old Chunk
chunkToSet.storageArrays[storageIndex].set(srcLocationPos.getX() & 15, srcLocationPos.getY() & 15, srcLocationPos.getZ() & 15, Blocks.AIR.getDefaultState());
// Delete the TileEntity at this pos (if there is one)
world.removeTileEntity(srcLocationPos);
chunkToSet.markDirty();
}
// Then relight the original chunks
{
Set<Long> chunksRelit = new HashSet<>();
blocksIterator = detector.foundSet.iterator();
while (blocksIterator.hasNext()) {
int hashedPos = blocksIterator.next();
SpatialDetector.setPosWithRespectTo(hashedPos, detector.firstBlock, srcLocationPos);
int changedChunkX = pasteLocationPos.getX() >> 4;
int changedChunkZ = pasteLocationPos.getZ() >> 4;
long changedChunkPos = ChunkPos.asLong(changedChunkX, changedChunkZ);
if (chunksRelit.contains(changedChunkPos)) {
continue;
}
final Chunk chunk = world.getChunk(changedChunkX, changedChunkZ);
chunk.generateSkylightMap();
chunk.checkLight();
chunk.markDirty();
chunksRelit.add(changedChunkPos);
}
}
// Then inject the ship chunks into the world
toSpawn.getChunkClaim().forEach((x, z) -> {
long chunkLong = ChunkPos.asLong(x, z);
if (copiedChunksMap.containsKey(chunkLong)) {
injectChunkIntoWorldServer(copiedChunksMap.get(chunkLong), x, z);
} else {
injectChunkIntoWorldServer(new Chunk(world, x, z), x, z);
}
});
// Add shipData to the ShipData storage
QueryableShipData.get(world).addShip(toSpawn);
// Finally, instantiate the PhysicsObject representation of this ShipData
PhysicsObject physicsObject = new PhysicsObject(world, toSpawn);
loadedShips.put(toSpawn.getUuid(), physicsObject);
}
spawnQueue.clear();
}
Aggregations