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;
}
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;
}
}
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) {
}
}
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());
}
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;
}
Aggregations