use of io.xol.chunkstories.api.entity.Entity in project chunkstories by Hugobros3.
the class WorldImplementation method addEntity.
@Override
public void addEntity(final Entity entity) {
// Assign an UUID to entities lacking one
if (this instanceof WorldMaster && entity.getUUID() == -1) {
long nextUUID = nextEntityId();
entity.setUUID(nextUUID);
}
Entity check = this.getEntityByUUID(entity.getUUID());
if (check != null) {
logger().error("Added an entity twice " + check + " conflits with " + entity + " UUID: " + entity.getUUID());
// logger().save();
Thread.dumpStack();
// System.exit(-1);
return;
}
// Add it to the world
((EntityBase) entity).markHasSpawned();
assert entity.getWorld() == this;
Chunk chunk = this.getChunkWorldCoordinates(entity.getLocation());
if (chunk != null) {
((EntityBase) entity).positionComponent.trySnappingToChunk();
}
this.entities.insertEntity(entity);
}
use of io.xol.chunkstories.api.entity.Entity in project chunkstories by Hugobros3.
the class ChunkHolderImplementation method unloadChunk.
private void unloadChunk() {
chunkLock.writeLock().lock();
CubicChunk chunk = this.chunk;
if (chunk == null) {
chunkLock.writeLock().unlock();
return;
}
// Unlist it immediately
regionLoadedChunks.remove(chunk);
this.chunk = null;
// Remove the entities from this chunk from the world
region.world.entitiesLock.writeLock().lock();
Iterator<Entity> i = chunk.localEntities.iterator();
while (i.hasNext()) {
Entity entity = i.next();
if (entity instanceof EntityControllable && ((EntityControllable) entity).getController() != null) {
// give grace to controlled entities
continue;
} else {
region.world.removeEntityFromList(entity);
}
}
region.world.entitiesLock.writeLock().unlock();
// Lock it down
chunk.entitiesLock.lock();
// Kill any load chunk operation that is still scheduled
if (loadChunkTask != null) {
IOTask task = loadChunkTask;
if (task != null)
task.cancel();
loadChunkTask = null;
}
// Compress chunk one last time before it has to go
setCompressedData(compressChunkData(chunk));
// destroy it (returns any internal data using up ressources)
chunk.destroy();
// unlock it (whoever messes with it now, his problem)
chunk.entitiesLock.unlock();
chunkLock.writeLock().unlock();
}
use of io.xol.chunkstories.api.entity.Entity in project chunkstories by Hugobros3.
the class ChunkHolderImplementation method compressChunkData.
/**
* This method is called assumming the chunk is well-locked
*/
private CompressedData compressChunkData(final CubicChunk chunk) {
final int changesTakenIntoAccount = chunk.compr_uncomittedBlockModifications.get();
// Stage 1: Compress the actual voxel data
byte[] voxelCompressedData;
if (!chunk.isAirChunk()) {
// Heuristic value for the size of the buffer: fixed voxel size + factor of components & entities
// + chunk.voxelComponents.size() * 1024 + chunk.localEntities.size() * 2048;
int uncompressedStuffBufferSize = 32 * 32 * 32 * 4;
ByteBuffer uncompressedStuff = MemoryUtil.memAlloc(uncompressedStuffBufferSize);
uncompressedStuff.asIntBuffer().put(chunk.chunkVoxelData);
// uncompressedStuff.flip();
ByteBuffer compressedStuff = MemoryUtil.memAlloc(uncompressedStuffBufferSize + 2048);
LZ4Compressor compressor = factory.fastCompressor();
compressor.compress(uncompressedStuff, compressedStuff);
// No longer need that buffer
MemoryUtil.memFree(uncompressedStuff);
// Make a Java byte[] array to put the final stuff in
voxelCompressedData = new byte[compressedStuff.position()];
compressedStuff.flip();
compressedStuff.get(voxelCompressedData);
// No longer need that buffer either
MemoryUtil.memFree(compressedStuff);
} else {
// Just use a symbolic null here
voxelCompressedData = null;
}
// Stage 2: Take care of the voxel components
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream daos = new DataOutputStream(baos);
// ByteBuffer smallBuffer = MemoryUtil.memAlloc(4096);
// byte[] smallArray = new byte[4096];
// ByteBufferOutputStream bbos = new ByteBufferOutputStream(smallBuffer);
ByteArrayOutputStream bbos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bbos);
try {
// For all cells that have components
for (CellComponentsHolder voxelComponents : chunk.allCellComponents.values()) {
// Write a 1 then their in-chunk index
daos.writeByte((byte) 0x01);
daos.writeInt(voxelComponents.getIndex());
// For all components in this cell
for (Entry<String, VoxelComponent> entry : voxelComponents.all()) {
// Write component name
daos.writeUTF(entry.getKey());
// Push the component in the temporary buffer
entry.getValue().push(region.handler, dos);
// smallBuffer.flip();
byte[] bytesPushed = bbos.toByteArray();
bbos.reset();
// Write how many bytes the temporary buffer now contains
// int bytesPushed = smallBuffer.limit();
daos.writeShort(bytesPushed.length);
// Get those bytes as an array then write it in the compressed stuff
// smallBuffer.get(smallArray);
daos.write(bytesPushed, 0, bytesPushed.length);
// Reset the temporary buffer
// smallBuffer.clear();
}
daos.writeUTF("\n");
}
// Write the final 00, so to be clear we are done with voxel components
daos.writeByte((byte) 0x00);
// Since we output to a local buffer, any failure is viewed as catastrophic
} catch (IOException e) {
assert false;
}
// Extract the byte array from the baos
byte[] voxelComponentsData = baos.toByteArray();
// MemoryUtil.memFree(smallBuffer);
// Stage 3: Compress entities
baos.reset();
for (Entity entity : chunk.localEntities) {
// Don't save controllable entities
if (entity.exists() && !(entity instanceof EntityUnsaveable && !((EntityUnsaveable) entity).shouldSaveIntoRegion())) {
EntitySerializer.writeEntityToStream(daos, region.handler, entity);
}
}
EntitySerializer.writeEntityToStream(daos, region.handler, null);
byte[] entityData = baos.toByteArray();
// Remove whatever modifications existed when the method started, this is for avoiding concurrent modifications not being taken into account
chunk.compr_uncomittedBlockModifications.addAndGet(-changesTakenIntoAccount);
return new CompressedData(voxelCompressedData, voxelComponentsData, entityData);
}
use of io.xol.chunkstories.api.entity.Entity in project chunkstories by Hugobros3.
the class WorldEntitiesHolder method getEntitiesInBox.
public NearEntitiesIterator getEntitiesInBox(Vector3dc center, Vector3dc boxSize) {
return new NearEntitiesIterator() {
int centerVoxel_x = (int) (double) center.x();
int centerVoxel_y = (int) (double) center.y();
int centerVoxel_z = (int) (double) center.z();
int box_ceil_x = (int) Math.ceil((double) boxSize.x());
int box_ceil_y = (int) Math.ceil((double) boxSize.y());
int box_ceil_z = (int) Math.ceil((double) boxSize.z());
int box_start_x = sanitizeHorizontalCoordinate(centerVoxel_x - box_ceil_x);
int box_start_y = sanitizeVerticalCoordinate(centerVoxel_y - box_ceil_y);
int box_start_z = sanitizeHorizontalCoordinate(centerVoxel_z - box_ceil_z);
int box_end_x = sanitizeHorizontalCoordinate(centerVoxel_x + box_ceil_x);
int box_end_y = sanitizeVerticalCoordinate(centerVoxel_y + box_ceil_y);
int box_end_z = sanitizeHorizontalCoordinate(centerVoxel_z + box_ceil_z);
// We currently sort this out by regions, chunks would be more appropriate ?
int region_start_x = box_start_x / 256;
int region_start_y = box_start_y / 256;
int region_start_z = box_start_z / 256;
int region_end_x = box_end_x / 256;
int region_end_y = box_end_y / 256;
int region_end_z = box_end_z / 256;
int region_x = region_start_x;
int region_y = region_start_y;
int region_z = region_start_z;
Region currentRegion = world.getRegion(region_x, region_y, region_z);
Iterator<Entity> currentRegionIterator = currentRegion == null ? null : currentRegion.getEntitiesWithinRegion();
Entity next = null;
double distance = 0D;
private void seekNextEntity() {
next = null;
while (true) {
// Break the loop if we find an entity in the region
if (seekNextEntityWithinRegion())
break;
else {
// Seek a suitable region if we failed to find anything above
if (seekNextRegion())
continue;
else
break;
}
}
}
private boolean seekNextEntityWithinRegion() {
if (currentRegionIterator == null)
return false;
while (currentRegionIterator.hasNext()) {
Entity entity = currentRegionIterator.next();
// Check if it's inside the box for realz
Location loc = entity.getLocation();
int locx = (int) (double) loc.x();
// Normal case, check if it's in the bounds, wrap-arround case, check if it's outside
if ((box_start_x > box_end_x) == (locx >= box_start_x && locx <= box_end_x))
continue;
int locy = (int) (double) loc.y();
// Normal case, check if it's in the bounds, wrap-arround case, check if it's outside
if ((box_start_y > box_end_y) == (locy >= box_start_y && locy <= box_end_y))
continue;
int locz = (int) (double) loc.z();
// Normal case, check if it's in the bounds, wrap-arround case, check if it's outside
if ((box_start_z > box_end_z) == (locz >= box_start_z && locz <= box_end_z))
continue;
// if(Math.abs(check.getX()) <= boxSize.getX() && Math.abs(check.getY()) <= boxSize.getY() && Math.abs(check.getZ()) <= boxSize.getZ())
{
// Found a good one
this.next = entity;
Vector3d check = new Vector3d(loc);
check.sub(center);
this.distance = check.length();
return true;
}
}
// We found nothing :(
currentRegionIterator = null;
return false;
}
private boolean seekNextRegion() {
currentRegion = null;
while (true) {
// Found one !
if (currentRegion != null) {
currentRegionIterator = currentRegion.getEntitiesWithinRegion();
return true;
}
region_x++;
// Wrap arround in X dimension to Y
if (region_x > region_end_x) {
region_x = 0;
region_y++;
}
// Then Y to Z
if (region_y > region_end_y) {
region_y = 0;
region_z++;
}
// We are done here
if (region_z > region_end_z)
return false;
currentRegion = world.getRegion(region_x, region_y, region_z);
}
}
@Override
public boolean hasNext() {
if (next == null)
seekNextEntity();
return next != null;
}
@Override
public Entity next() {
Entity entity = next;
seekNextEntity();
return entity;
}
@Override
public double distance() {
return distance;
}
};
}
use of io.xol.chunkstories.api.entity.Entity in project chunkstories by Hugobros3.
the class WorldRendererImplementation method blitFinalImage.
public void blitFinalImage(RenderingInterface renderingContext, boolean hideGui) {
Texture finalBuffer = this.renderingGraph.getRenderPass("final").resolvedOutputs.get("finalBuffer");
if (finalBuffer != null && finalBuffer instanceof Texture2D) {
final Texture2D finalTexture = (Texture2D) (finalBuffer);
// We render to the screen.
renderingContext.getRenderTargetManager().setConfiguration(null);
renderingContext.setDepthTestMode(DepthTestMode.DISABLED);
renderingContext.setBlendMode(BlendMode.DISABLED);
renderingContext.useShader("blit");
renderingContext.bindTexture2D("diffuseTexture", finalTexture);
renderingContext.drawFSQuad();
if (!hideGui) {
world.entitiesLock.readLock().lock();
Iterator<Entity> ei = world.getAllLoadedEntities();
Entity e;
while (ei.hasNext()) {
e = ei.next();
if (e instanceof EntityOverlay) {
((EntityOverlay) e).drawEntityOverlay(renderingContext);
}
}
world.entitiesLock.readLock().unlock();
}
}
}
Aggregations