Search in sources :

Example 16 with ShipData

use of org.valkyrienskies.mod.common.ships.ShipData in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.

the class MoveBlocks method copyTileEntityToPos.

public static void copyTileEntityToPos(World world, BlockPos oldPos, BlockPos newPos, PhysicsObject physicsObject) {
    // Make a copy of the tile entity at oldPos to newPos
    TileEntity worldTile = world.getTileEntity(oldPos);
    if (worldTile != null) {
        NBTTagCompound tileEntNBT = new NBTTagCompound();
        TileEntity newInstance;
        if (worldTile instanceof IRelocationAwareTile) {
            ShipData shipData = null;
            if (physicsObject != null) {
                shipData = physicsObject.getShipData();
            }
            newInstance = ((IRelocationAwareTile) worldTile).createRelocatedTile(newPos, shipData);
        } else {
            tileEntNBT = worldTile.writeToNBT(tileEntNBT);
            // Change the block position to be inside of the Ship
            tileEntNBT.setInteger("x", newPos.getX());
            tileEntNBT.setInteger("y", newPos.getY());
            tileEntNBT.setInteger("z", newPos.getZ());
            newInstance = TileEntity.create(world, tileEntNBT);
        }
        try {
            world.setTileEntity(newPos, newInstance);
            if (physicsObject != null) {
                physicsObject.onSetTileEntity(newPos, newInstance);
            }
            newInstance.markDirty();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Also used : TileEntity(net.minecraft.tileentity.TileEntity) ShipData(org.valkyrienskies.mod.common.ships.ShipData) NBTTagCompound(net.minecraft.nbt.NBTTagCompound)

Example 17 with ShipData

use of org.valkyrienskies.mod.common.ships.ShipData in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.

the class WorldServerShipManager method getBackgroundShipChunks.

/**
 * Used to prevent the world from unloading the chunks of ships loading in background.
 */
public Iterable<Long> getBackgroundShipChunks() throws CalledFromWrongThreadException {
    enforceGameThread();
    List<Long> backgroundChunks = new ArrayList<>();
    QueryableShipData queryableShipData = QueryableShipData.get(world);
    for (UUID shipID : loadingInBackground) {
        Optional<ShipData> shipDataOptional = queryableShipData.getShip(shipID);
        if (!shipDataOptional.isPresent()) {
            throw new IllegalStateException("Ship data not present for:\n" + shipID);
        }
        backgroundChunks.addAll(shipDataOptional.get().getChunkClaim().getClaimedChunks());
    }
    return backgroundChunks;
}
Also used : QueryableShipData(org.valkyrienskies.mod.common.ships.QueryableShipData) ShipData(org.valkyrienskies.mod.common.ships.ShipData) QueryableShipData(org.valkyrienskies.mod.common.ships.QueryableShipData)

Example 18 with ShipData

use of org.valkyrienskies.mod.common.ships.ShipData 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)

Example 19 with ShipData

use of org.valkyrienskies.mod.common.ships.ShipData in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.

the class WorldServerShipManager method loadAndUnloadShips.

private void loadAndUnloadShips() {
    QueryableShipData queryableShipData = QueryableShipData.get(world);
    // Load the ships that are required immediately.
    for (final UUID toLoadID : loadQueue) {
        Optional<ShipData> toLoadOptional = queryableShipData.getShip(toLoadID);
        if (!toLoadOptional.isPresent()) {
            throw new IllegalStateException("No ship found for ID:\n" + toLoadID);
        }
        ShipData toLoad = toLoadOptional.get();
        if (loadedShips.containsKey(toLoadID)) {
            throw new IllegalStateException("Tried loading a ShipData that was already loaded?\n" + toLoad);
        }
        // Remove this ship from the background loading set, if it is in it.
        loadingInBackground.remove(toLoadID);
        // Finally, load the ship.
        if (VSConfig.showAnnoyingDebugOutput) {
            System.out.println("Attempting to load ship " + toLoad);
        }
        PhysicsObject physicsObject = new PhysicsObject(world, toLoad);
        PhysicsObject old = loadedShips.put(toLoad.getUuid(), physicsObject);
        if (old != null) {
            throw new IllegalStateException("How did we already have a ship loaded for " + toLoad);
        }
    }
    loadQueue.clear();
    // Load ships that aren't required immediately in the background.
    for (final UUID toLoadID : backgroundLoadQueue) {
        // Skip if this ship is already being loaded in the background,.
        if (loadingInBackground.contains(toLoadID)) {
            // Already loading this ship in the background
            continue;
        }
        // Make sure there isn't an already loaded ship with this UUID.
        if (loadedShips.containsKey(toLoadID)) {
            // continue; // temp, need to fix WorldShipLoadingController.determineLoadAndUnload()
            throw new IllegalStateException("Tried loading a ShipData that was already loaded? Ship ID is\n" + toLoadID);
        }
        // Then try getting the ShipData for this UUID.
        Optional<ShipData> toLoadOptional = queryableShipData.getShip(toLoadID);
        if (!toLoadOptional.isPresent()) {
            throw new IllegalStateException("No ship found for ID:\n" + toLoadID);
        }
        ShipData toLoad = toLoadOptional.get();
        loadingInBackground.add(toLoadID);
        if (VSConfig.showAnnoyingDebugOutput) {
            System.out.println("Attempting to load " + toLoad + " in the background.");
        }
        ChunkProviderServer chunkProviderServer = world.getChunkProvider();
        for (ChunkPos chunkPos : toLoad.getChunkClaim()) {
            @Nonnull Runnable returnTask = () -> {
                if (VSConfig.showAnnoyingDebugOutput) {
                    System.out.println("Loaded ship chunk " + chunkPos);
                }
            };
            chunkProviderServer.loadChunk(chunkPos.x, chunkPos.z, returnTask);
        }
    }
    backgroundLoadQueue.clear();
    // Unload far away ships immediately.
    for (final UUID toUnloadID : unloadQueue) {
        // Make sure we have a ship with this ID that can be unloaded
        if (!loadedShips.containsKey(toUnloadID)) {
            throw new IllegalStateException("Tried unloading a ShipData that isn't loaded? Ship ID is\n" + toUnloadID);
        }
        PhysicsObject physicsObject = getPhysObjectFromUUID(toUnloadID);
        if (VSConfig.showAnnoyingDebugOutput) {
            System.out.println("Attempting to unload " + physicsObject);
        }
        physicsObject.unload();
        boolean success = loadedShips.remove(toUnloadID, physicsObject);
        if (!success) {
            throw new IllegalStateException("How did we fail to unload " + physicsObject.getShipData());
        }
    }
    unloadQueue.clear();
}
Also used : Nonnull(javax.annotation.Nonnull) QueryableShipData(org.valkyrienskies.mod.common.ships.QueryableShipData) ShipData(org.valkyrienskies.mod.common.ships.ShipData) ChunkProviderServer(net.minecraft.world.gen.ChunkProviderServer) ChunkPos(net.minecraft.util.math.ChunkPos) QueryableShipData(org.valkyrienskies.mod.common.ships.QueryableShipData)

Example 20 with ShipData

use of org.valkyrienskies.mod.common.ships.ShipData in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.

the class WorldShipLoadingController method updateWatchingPlayers.

/**
 * Determine which ships are watched by which players.
 */
private Map<ShipData, Set<EntityPlayerMP>> updateWatchingPlayers() {
    Map<ShipData, Set<EntityPlayerMP>> newWatching = new HashMap<>();
    // Copy the old watching to the new, making sure not to copy data from ships that got unloaded.
    for (PhysicsObject ship : shipManager.getAllLoadedPhysObj()) {
        ShipData shipData = ship.getShipData();
        if (shipToWatchingPlayers.containsKey(shipData)) {
            Set<EntityPlayerMP> oldWatchingPlayers = shipToWatchingPlayers.get(shipData);
            Set<EntityPlayerMP> newWatchingPlayers = new HashSet<>();
            // Do this to prevent players who left the game from propagating to future watching maps.
            for (EntityPlayer player : shipManager.getWorld().playerEntities) {
                if (oldWatchingPlayers.contains(player)) {
                    newWatchingPlayers.add((EntityPlayerMP) player);
                }
            }
            newWatching.put(shipData, newWatchingPlayers);
        } else {
            newWatching.put(shipData, new HashSet<>());
        }
    }
    // Remove players that aren't watching anymore, and add new watching players
    for (PhysicsObject ship : shipManager.getAllLoadedPhysObj()) {
        Vec3d shipPos = ship.getShipTransform().getShipPositionVec3d();
        // Remove players further than the unwatch distance
        newWatching.get(ship.getShipData()).removeIf(watcher -> !isPlayerWithinDistanceXZ(watcher, shipPos, VSConfig.SHIP_LOADING_SETTINGS.unwatchDistance));
        // Add players closer than the watch distance
        for (EntityPlayer player : shipManager.getWorld().playerEntities) {
            if (isPlayerWithinDistanceXZ(player, shipPos, VSConfig.SHIP_LOADING_SETTINGS.watchDistance)) {
                newWatching.get(ship.getShipData()).add((EntityPlayerMP) player);
            }
        }
    }
    return newWatching;
}
Also used : ShipData(org.valkyrienskies.mod.common.ships.ShipData) QueryableShipData(org.valkyrienskies.mod.common.ships.QueryableShipData) EntityPlayer(net.minecraft.entity.player.EntityPlayer) EntityPlayerMP(net.minecraft.entity.player.EntityPlayerMP) Vec3d(net.minecraft.util.math.Vec3d)

Aggregations

ShipData (org.valkyrienskies.mod.common.ships.ShipData)25 QueryableShipData (org.valkyrienskies.mod.common.ships.QueryableShipData)14 Vector3d (org.joml.Vector3d)9 ShipTransform (org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform)6 Chunk (net.minecraft.world.chunk.Chunk)4 UUID (java.util.UUID)3 IBlockState (net.minecraft.block.state.IBlockState)3 EntityPlayer (net.minecraft.entity.player.EntityPlayer)3 EntityPlayerMP (net.minecraft.entity.player.EntityPlayerMP)3 NBTTagCompound (net.minecraft.nbt.NBTTagCompound)3 BlockPos (net.minecraft.util.math.BlockPos)3 Vec3d (net.minecraft.util.math.Vec3d)3 World (net.minecraft.world.World)3 Inject (org.spongepowered.asm.mixin.injection.Inject)3 EntityLivingBase (net.minecraft.entity.EntityLivingBase)2 PacketBuffer (net.minecraft.network.PacketBuffer)2 TileEntity (net.minecraft.tileentity.TileEntity)2 ChunkPos (net.minecraft.util.math.ChunkPos)2 TextComponentString (net.minecraft.util.text.TextComponentString)2 WorldServer (net.minecraft.world.WorldServer)2