Search in sources :

Example 26 with BlockRegion

use of org.terasology.engine.world.block.BlockRegion in project Terasology by MovingBlocks.

the class HeadlessWorldRenderer method updateChunksInProximity.

/**
 * Updates the list of chunks around the player.
 *
 * @param force Forces the update
 * @return True if the list was changed
 */
public boolean updateChunksInProximity(boolean force) {
    Vector3i newChunkPos = calcCamChunkOffset();
    // TODO: This should actually be done based on events from the ChunkProvider on new chunk availability/old chunk removal
    boolean chunksCurrentlyPending = false;
    if (!newChunkPos.equals(chunkPos) || force || pendingChunks) {
        Vector3ic viewingDistance = config.getRendering().getViewDistance().getChunkDistance();
        BlockRegion viewRegion = new BlockRegion(newChunkPos).expand(new Vector3i(viewingDistance.x() / 2, viewingDistance.y() / 2, viewingDistance.z() / 2));
        if (chunksInProximity.size() == 0 || force || pendingChunks) {
            // just add all visible chunks
            chunksInProximity.clear();
            for (Vector3ic chunkPosition : viewRegion) {
                Chunk c = chunkProvider.getChunk(chunkPosition);
                if (c != null && worldProvider.getLocalView(c.getPosition(new Vector3i())) != null) {
                    chunksInProximity.add(c);
                } else {
                    chunksCurrentlyPending = true;
                }
            }
        } else {
            BlockRegion oldRegion = new BlockRegion(chunkPos).expand(new Vector3i(viewingDistance.x() / 2, viewingDistance.y() / 2, viewingDistance.z() / 2));
            // remove
            for (Vector3ic candidateForRemove : viewRegion) {
                if (!oldRegion.contains(candidateForRemove)) {
                    Chunk c = chunkProvider.getChunk(candidateForRemove);
                    if (c != null) {
                        chunksInProximity.remove(c);
                        c.disposeMesh();
                    }
                }
            }
            // add
            for (Vector3ic chunkPosition : viewRegion) {
                Chunk c = chunkProvider.getChunk(chunkPosition);
                if (c != null && worldProvider.getLocalView(c.getPosition(new Vector3i())) != null) {
                    chunksInProximity.add(c);
                } else {
                    chunksCurrentlyPending = true;
                }
            }
        }
        chunkPos.set(newChunkPos);
        pendingChunks = chunksCurrentlyPending;
        Collections.sort(chunksInProximity, new ChunkFrontToBackComparator());
        return true;
    }
    return false;
}
Also used : Vector3ic(org.joml.Vector3ic) Vector3i(org.joml.Vector3i) BlockRegion(org.terasology.engine.world.block.BlockRegion) RenderableChunk(org.terasology.engine.world.chunks.RenderableChunk) Chunk(org.terasology.engine.world.chunks.Chunk)

Example 27 with BlockRegion

use of org.terasology.engine.world.block.BlockRegion in project Terasology by MovingBlocks.

the class AbstractSpawner method getStartHeight.

/**
 * Get the elevation at a single point, to use as the base point for searching.
 */
private int getStartHeight(World world, Vector2i pos) {
    BlockRegion spawnArea = new BlockRegion(pos.x(), 0, pos.y());
    Region worldRegion = world.getWorldData(spawnArea);
    ElevationFacet elevationFacet = worldRegion.getFacet(ElevationFacet.class);
    if (elevationFacet != null) {
        return (int) elevationFacet.getWorld(pos);
    } else {
        // We'll have to rely on the SurfaceHeightFacet or SpawnHeightFacet anyway, and those are purely 2D so the height doesn't matter.
        return 0;
    }
}
Also used : BlockRegion(org.terasology.engine.world.block.BlockRegion) Region(org.terasology.engine.world.generation.Region) BlockRegion(org.terasology.engine.world.block.BlockRegion) ElevationFacet(org.terasology.engine.world.generation.facets.ElevationFacet)

Example 28 with BlockRegion

use of org.terasology.engine.world.block.BlockRegion in project Terasology by MovingBlocks.

the class LodChunkProvider method createChunks.

private void createChunks() {
    Block unloaded = blockManager.getBlock(BlockManager.UNLOADED_ID);
    try {
        while (true) {
            Vector3ic pos = neededChunks.take();
            // Actually the log scale
            Integer scale = requiredChunks.get(pos);
            if (scale == null) {
                // This chunk is being removed in the main thread.
                continue;
            }
            Chunk chunk = new PreLodChunk(scaleDown(pos, scale), blockManager, extraDataManager);
            generator.createChunk(chunk, (1 << scale) * (2f / (Chunks.SIZE_X - 2) + 1));
            InternalLightProcessor.generateInternalLighting(chunk, 1 << scale);
            // tintChunk(chunk);
            ChunkView view = new ChunkViewCoreImpl(new Chunk[] { chunk }, new BlockRegion(chunk.getPosition(new Vector3i())), new Vector3i(), unloaded);
            ChunkMesh mesh = tessellator.generateMesh(view, 1 << scale, 1);
            readyChunks.add(new LodChunk(pos, mesh, scale));
        }
    } catch (InterruptedException ignored) {
    }
}
Also used : PreLodChunk(org.terasology.engine.world.chunks.internal.PreLodChunk) ChunkViewCoreImpl(org.terasology.engine.world.internal.ChunkViewCoreImpl) ChunkMesh(org.terasology.engine.rendering.primitives.ChunkMesh) Vector3ic(org.joml.Vector3ic) Vector3i(org.joml.Vector3i) Block(org.terasology.engine.world.block.Block) BlockRegion(org.terasology.engine.world.block.BlockRegion) PreLodChunk(org.terasology.engine.world.chunks.internal.PreLodChunk) PreLodChunk(org.terasology.engine.world.chunks.internal.PreLodChunk) ChunkView(org.terasology.engine.world.ChunkView)

Example 29 with BlockRegion

use of org.terasology.engine.world.block.BlockRegion in project Terasology by MovingBlocks.

the class RelevanceSystem method addRelevanceEntity.

/**
 * Add entity to relevance system. create region for it. Update distance if region exists already. Create/Load
 * chunks for region.
 *
 * @param entity the region will be centered around the LocationComponent of this entity
 * @param distance the dimensions of the region, in chunks
 * @param listener notified when relevant chunks become available
 *
 * @return the region of chunks deemed relevant
 */
public BlockRegionc addRelevanceEntity(EntityRef entity, Vector3ic distance, ChunkRegionListener listener) {
    if (!entity.exists()) {
        // Futures.immediateFailedFuture(new IllegalArgumentException("Entity does not exist."));
        return null;
    }
    regionLock.readLock().lock();
    try {
        ChunkRelevanceRegion region = regions.get(entity);
        if (region != null) {
            region.setRelevanceDistance(distance);
            // Future of “when region.currentRegion is no longer dirty”?
            return new BlockRegion(region.getCurrentRegion());
        }
    } finally {
        regionLock.readLock().unlock();
    }
    ChunkRelevanceRegion region = new ChunkRelevanceRegion(entity, distance);
    if (listener != null) {
        region.setListener(listener);
    }
    regionLock.writeLock().lock();
    try {
        regions.put(entity, region);
    } finally {
        regionLock.writeLock().unlock();
    }
    StreamSupport.stream(region.getCurrentRegion().spliterator(), false).sorted(// <-- this is n^2 cost. not sure why this needs to be sorted like this.
    new PositionRelevanceComparator()).forEach(pos -> {
        Chunk chunk = chunkProvider.getChunk(pos);
        if (chunk != null) {
            region.checkIfChunkIsRelevant(chunk);
        // return Futures.immediateFuture(chunk);
        } else {
            // return this
            chunkProvider.createOrLoadChunk(pos);
        }
    });
    // whenAllComplete
    return new BlockRegion(region.getCurrentRegion());
}
Also used : ChunkRelevanceRegion(org.terasology.engine.world.chunks.internal.ChunkRelevanceRegion) BlockRegion(org.terasology.engine.world.block.BlockRegion) Chunk(org.terasology.engine.world.chunks.Chunk)

Example 30 with BlockRegion

use of org.terasology.engine.world.block.BlockRegion in project Terasology by MovingBlocks.

the class LodChunkProvider method updateRenderableRegion.

public void updateRenderableRegion(ViewDistance newViewDistance, int newChunkLods, Vector3i newCenter) {
    viewDistanceSetting = newViewDistance;
    center = new Vector3i(delay(center.x, newCenter.x), delay(center.y, newCenter.y), delay(center.z, newCenter.z));
    chunkLods = newChunkLods;
    nearby.pos = center;
    Vector3i viewDistance = new Vector3i(newViewDistance.getChunkDistance()).div(2);
    Vector3i altViewDistance = viewDistance.add(1 - Math.abs(viewDistance.x % 2), 1 - Math.abs(viewDistance.y % 2), 1 - Math.abs(viewDistance.z % 2), new Vector3i());
    BlockRegion newPossiblyLoadedRegion = new BlockRegion(newCenter).expand(viewDistance);
    BlockRegion newProbablyLoadedRegion = new BlockRegion(newPossiblyLoadedRegion).expand(-1, -1, -1);
    BlockRegion[] newLodRegions = new BlockRegion[newChunkLods == 0 ? 0 : 1 + newChunkLods];
    while (chunks.size() < newLodRegions.length) {
        chunks.add(new ConcurrentHashMap<>());
    }
    while (chunks.size() > newLodRegions.length) {
        for (LodChunk chunk : chunks.remove(chunks.size() - 1).values()) {
            chunk.disposeMesh();
        }
    }
    boolean lodRegionChange = newLodRegions.length != lodRegions.length;
    for (int i = 0; i < newLodRegions.length; i++) {
        if (i == 0) {
            newLodRegions[i] = new BlockRegion(newPossiblyLoadedRegion);
        } else {
            // By making viewDistance odd, we ensure that every time a chunk boundary is crossed, at most a single
            // lodRegion changes (except possibly for lodRegions[0], which is more closely tied to the renderable
            // region).
            newLodRegions[i] = new BlockRegion(scaleDown(center, i)).expand(altViewDistance);
        }
        Vector3i min = newLodRegions[i].getMin(new Vector3i());
        Vector3i max = newLodRegions[i].getMax(new Vector3i());
        newLodRegions[i].addToMin(-Math.abs(min.x % 2), -Math.abs(min.y % 2), -Math.abs(min.z % 2));
        newLodRegions[i].addToMax(1 - Math.abs(max.x % 2), 1 - Math.abs(max.y % 2), 1 - Math.abs(max.z % 2));
        if (!lodRegionChange && !newLodRegions[i].equals(lodRegions[i])) {
            lodRegionChange = true;
        }
    }
    if (lodRegionChange || !newProbablyLoadedRegion.equals(probablyLoadedRegion) || !newPossiblyLoadedRegion.equals(possiblyLoadedRegion)) {
        // Remove previously present chunks.
        Set<Vector3ic> previouslyRequiredChunks = new HashSet<>(requiredChunks.keySet());
        for (Vector3ic pos : previouslyRequiredChunks) {
            int scale = requiredChunks.get(pos);
            // Whether this entry in requiredChunks should be removed entirely (i.e. the chunk at the actually
            // required scale is not at this position).
            boolean gone = false;
            boolean increased = false;
            while (scale < newLodRegions.length && !gone && !newLodRegions[scale].contains(scaleDown(pos, scale))) {
                LodChunk chunk = chunks.get(scale).get(new Vector3i(pos));
                if (chunk != null) {
                    chunk.disposeMesh();
                    chunks.get(scale).remove(new Vector3i(pos));
                }
                gone = ((pos.x() | pos.y() | pos.z()) & (1 << scale)) != 0;
                scale++;
                increased = true;
            }
            if (gone || scale >= newLodRegions.length) {
                neededChunks.remove(pos);
                requiredChunks.remove(pos);
            } else if (increased) {
                LodChunk chunk = chunks.get(scale).get(new Vector3i(pos));
                if (chunk != null) {
                    requiredChunks.put(new Vector3i(pos), scale);
                    chunk.hiddenness = 0;
                } else {
                    requiredChunks.remove(pos);
                }
            }
        }
        // Add new chunks.
        for (int scale = 0; scale < newLodRegions.length; scale++) {
            for (Vector3ic pos : newLodRegions[scale]) {
                if (scale == 0 && newProbablyLoadedRegion.contains(pos) || scale == 0 && newPossiblyLoadedRegion.contains(pos) && chunkProvider.isChunkReady(pos) || scale > 0 && newLodRegions[scale - 1].contains(pos.mul(2, new Vector3i()))) {
                    continue;
                }
                Vector3i globalPos = pos.mul(1 << scale, new Vector3i());
                Integer previousScale = requiredChunks.get(globalPos);
                if (previousScale == null || previousScale > scale) {
                    addChunk(globalPos, scale);
                }
            }
        }
    }
    lodRegions = newLodRegions;
    probablyLoadedRegion = newProbablyLoadedRegion;
    possiblyLoadedRegion = newPossiblyLoadedRegion;
}
Also used : Vector3ic(org.joml.Vector3ic) Vector3i(org.joml.Vector3i) BlockRegion(org.terasology.engine.world.block.BlockRegion) PreLodChunk(org.terasology.engine.world.chunks.internal.PreLodChunk) HashSet(java.util.HashSet)

Aggregations

BlockRegion (org.terasology.engine.world.block.BlockRegion)52 Vector3i (org.joml.Vector3i)29 Vector3ic (org.joml.Vector3ic)26 Test (org.junit.jupiter.api.Test)26 Chunk (org.terasology.engine.world.chunks.Chunk)23 ChunkImpl (org.terasology.engine.world.chunks.internal.ChunkImpl)11 ChunkViewCoreImpl (org.terasology.engine.world.internal.ChunkViewCoreImpl)7 ChunkViewCore (org.terasology.engine.world.internal.ChunkViewCore)5 Vector3f (org.joml.Vector3f)4 BeforeEach (org.junit.jupiter.api.BeforeEach)4 ReceiveEvent (org.terasology.engine.entitySystem.event.ReceiveEvent)4 Border3D (org.terasology.engine.world.generation.Border3D)4 WorldGeneratorPluginLibrary (org.terasology.engine.world.generator.plugin.WorldGeneratorPluginLibrary)4 ElevationFacet (org.terasology.engine.world.generation.facets.ElevationFacet)3 Vector2ic (org.joml.Vector2ic)2 RenderableChunk (org.terasology.engine.world.chunks.RenderableChunk)2 PreLodChunk (org.terasology.engine.world.chunks.internal.PreLodChunk)2 Region (org.terasology.engine.world.generation.Region)2 World (org.terasology.engine.world.generation.World)2 JsonElement (com.google.gson.JsonElement)1