Search in sources :

Example 1 with SpatialDetector

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();
}
Also used : IPhysicsObjectCenterOfMassProvider(org.valkyrienskies.mod.common.ships.physics_data.IPhysicsObjectCenterOfMassProvider) NBTTagCompound(net.minecraft.nbt.NBTTagCompound) TileEntity(net.minecraft.tileentity.TileEntity) IRelocationAwareTile(org.valkyrienskies.mod.common.ships.block_relocation.IRelocationAwareTile) BasicCenterOfMassProvider(org.valkyrienskies.mod.common.ships.physics_data.BasicCenterOfMassProvider) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos) BlockPos(net.minecraft.util.math.BlockPos) ChunkPos(net.minecraft.util.math.ChunkPos) TIntIterator(gnu.trove.iterator.TIntIterator) IBlockState(net.minecraft.block.state.IBlockState) QueryableShipData(org.valkyrienskies.mod.common.ships.QueryableShipData) ShipData(org.valkyrienskies.mod.common.ships.ShipData) BlockFinder(org.valkyrienskies.mod.common.ships.block_relocation.BlockFinder) Chunk(net.minecraft.world.chunk.Chunk) ExtendedBlockStorage(net.minecraft.world.chunk.storage.ExtendedBlockStorage) SpatialDetector(org.valkyrienskies.mod.common.ships.block_relocation.SpatialDetector) MutableBlockPos(net.minecraft.util.math.BlockPos.MutableBlockPos)

Aggregations

TIntIterator (gnu.trove.iterator.TIntIterator)1 IBlockState (net.minecraft.block.state.IBlockState)1 NBTTagCompound (net.minecraft.nbt.NBTTagCompound)1 TileEntity (net.minecraft.tileentity.TileEntity)1 BlockPos (net.minecraft.util.math.BlockPos)1 MutableBlockPos (net.minecraft.util.math.BlockPos.MutableBlockPos)1 ChunkPos (net.minecraft.util.math.ChunkPos)1 Chunk (net.minecraft.world.chunk.Chunk)1 ExtendedBlockStorage (net.minecraft.world.chunk.storage.ExtendedBlockStorage)1 QueryableShipData (org.valkyrienskies.mod.common.ships.QueryableShipData)1 ShipData (org.valkyrienskies.mod.common.ships.ShipData)1 BlockFinder (org.valkyrienskies.mod.common.ships.block_relocation.BlockFinder)1 IRelocationAwareTile (org.valkyrienskies.mod.common.ships.block_relocation.IRelocationAwareTile)1 SpatialDetector (org.valkyrienskies.mod.common.ships.block_relocation.SpatialDetector)1 BasicCenterOfMassProvider (org.valkyrienskies.mod.common.ships.physics_data.BasicCenterOfMassProvider)1 IPhysicsObjectCenterOfMassProvider (org.valkyrienskies.mod.common.ships.physics_data.IPhysicsObjectCenterOfMassProvider)1