terrain streams without allocations
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-05-26 15:06:03 -04:00
parent 0d77c4e571
commit c7cd9dfa34
10 changed files with 174 additions and 54 deletions

View File

@ -90,6 +90,14 @@ public class ChunkData {
this.homogenousValue = homogenousValue; this.homogenousValue = homogenousValue;
} }
/**
* Creates a chunk data object
*/
public ChunkData(){
this.voxelWeight = new float[ChunkData.CHUNK_DATA_SIZE][ChunkData.CHUNK_DATA_SIZE][ChunkData.CHUNK_DATA_SIZE];
this.voxelType = new int[ChunkData.CHUNK_DATA_SIZE][ChunkData.CHUNK_DATA_SIZE][ChunkData.CHUNK_DATA_SIZE];
}
/** /**
* Gets the voxel type array in this container * Gets the voxel type array in this container
@ -193,6 +201,17 @@ public class ChunkData {
return voxelWeight[localX][localY][localZ]; return voxelWeight[localX][localY][localZ];
} }
/**
* Sets the weight of a voxel at a poisiton
* @param localX The x coordinate
* @param localY The y coordinate
* @param localZ The z coordinate
* @param weight THe value
*/
public void setWeight(int localX, int localY, int localZ, float weight){
voxelWeight[localX][localY][localZ] = weight;
}
/** /**
* Gets the type of a voxel at a position * Gets the type of a voxel at a position
* @param localPosition The local position * @param localPosition The local position
@ -202,6 +221,17 @@ public class ChunkData {
return getType(localPosition.x,localPosition.y,localPosition.z); return getType(localPosition.x,localPosition.y,localPosition.z);
} }
/**
* Sets the type of a voxel at a position
* @param localX The x coordinate
* @param localY The y coordinate
* @param localZ The z coordinate
* @param type The type value
*/
public void setType(int localX, int localY, int localZ, int type){
voxelType[localX][localY][localZ] = type;
}
/** /**
* Gets the type of a voxel at a position * Gets the type of a voxel at a position
* @param localX The x coordinate * @param localX The x coordinate
@ -271,5 +301,27 @@ public class ChunkData {
return homogenousValue; return homogenousValue;
} }
public void setWorldX(int worldX) {
this.worldX = worldX;
}
public void setWorldY(int worldY) {
this.worldY = worldY;
}
public void setWorldZ(int worldZ) {
this.worldZ = worldZ;
}
public void setStride(int stride) {
this.stride = stride;
}
public void setHomogenousValue(int homogenousValue) {
this.homogenousValue = homogenousValue;
}
} }

View File

@ -4,6 +4,8 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import electrosphere.client.terrain.cache.ChunkData;
/** /**
* Pools allocated terrain chunk data objects * Pools allocated terrain chunk data objects
*/ */
@ -12,7 +14,12 @@ public class TerrainChunkDataPool {
/** /**
* Structure to store not-in-use objects * Structure to store not-in-use objects
*/ */
static List<TerrainChunkData> pool = new LinkedList<TerrainChunkData>(); static List<TerrainChunkData> meshPool = new LinkedList<TerrainChunkData>();
/**
* Structure to store not-in-use objects
*/
static List<ChunkData> dataPool = new LinkedList<ChunkData>();
/** /**
* Lock for thread-safeing operations * Lock for thread-safeing operations
@ -23,11 +30,11 @@ public class TerrainChunkDataPool {
* Gets a terrain chunk object from the pool. Allocates if no free one is available. * Gets a terrain chunk object from the pool. Allocates if no free one is available.
* @return A terrain chunk object of the requested type * @return A terrain chunk object of the requested type
*/ */
public static TerrainChunkData get(){ public static TerrainChunkData getMesh(){
TerrainChunkData rVal = null; TerrainChunkData rVal = null;
lock.lock(); lock.lock();
if(pool.size() > 0){ if(meshPool.size() > 0){
rVal = pool.remove(0); rVal = meshPool.remove(0);
} else { } else {
rVal = new TerrainChunkData(); rVal = new TerrainChunkData();
} }
@ -41,7 +48,33 @@ public class TerrainChunkDataPool {
*/ */
public static void release(TerrainChunkData data){ public static void release(TerrainChunkData data){
lock.lock(); lock.lock();
TerrainChunkDataPool.pool.add(data); TerrainChunkDataPool.meshPool.add(data);
lock.unlock();
}
/**
* Gets a terrain chunk object from the pool. Allocates if no free one is available.
* @return A terrain chunk object of the requested type
*/
public static ChunkData getData(){
ChunkData rVal = null;
lock.lock();
if(dataPool.size() > 0){
rVal = dataPool.remove(0);
} else {
rVal = new ChunkData();
}
lock.unlock();
return rVal;
}
/**
* Releases a terrain chunk data object back into the pool
* @param data The object to release
*/
public static void release(ChunkData data){
lock.lock();
TerrainChunkDataPool.dataPool.add(data);
lock.unlock(); lock.unlock();
} }
@ -50,7 +83,7 @@ public class TerrainChunkDataPool {
* @return The size of the chunk pool * @return The size of the chunk pool
*/ */
public static int getPoolSize(){ public static int getPoolSize(){
return pool.size(); return meshPool.size();
} }
} }

View File

@ -151,38 +151,8 @@ public class ClientTerrainManager {
); );
} break; } break;
case SENDREDUCEDCHUNKDATA: { case SENDREDUCEDCHUNKDATA: {
ChunkData data = new ChunkData(message.getworldX(), message.getworldY(), message.getworldZ(), message.getchunkResolution(), message.gethomogenousValue()); ChunkData data = (ChunkData)message.getExtraData().get(0);
if(message.gethomogenousValue() == ChunkData.NOT_HOMOGENOUS){ message.getExtraData().clear();
int[][][] values = new int[ChunkData.CHUNK_DATA_SIZE][ChunkData.CHUNK_DATA_SIZE][ChunkData.CHUNK_DATA_SIZE];
float[][][] weights = new float[ChunkData.CHUNK_DATA_SIZE][ChunkData.CHUNK_DATA_SIZE][ChunkData.CHUNK_DATA_SIZE];
ByteBuffer buffer = ByteBuffer.wrap(message.getchunkData());
FloatBuffer floatBuffer = buffer.asFloatBuffer();
for(int x = 0; x < ChunkData.CHUNK_DATA_SIZE; x++){
for(int z = 0; z < ChunkData.CHUNK_DATA_SIZE; z++){
for(int y = 0; y < ChunkData.CHUNK_DATA_SIZE; y++){
weights[x][y][z] = floatBuffer.get();
}
}
}
IntBuffer intView = buffer.asIntBuffer();
intView.position(floatBuffer.position());
int firstType = -1;
boolean homogenous = true;
for(int x = 0; x < ChunkData.CHUNK_DATA_SIZE; x++){
for(int z = 0; z < ChunkData.CHUNK_DATA_SIZE; z++){
for(int y = 0; y < ChunkData.CHUNK_DATA_SIZE; y++){
values[x][y][z] = intView.get();
if(firstType == -1){
firstType = values[x][y][z];
} else if(homogenous && firstType == values[x][y][z]){
homogenous = false;
}
}
}
}
data.setVoxelType(values);
data.setVoxelWeight(weights);
}
if(message.getchunkResolution() == ChunkData.NO_STRIDE && terrainCache.containsChunkDataAtWorldPoint(message.getworldX(), message.getworldY(), message.getworldZ(), ChunkData.NO_STRIDE)){ if(message.getchunkResolution() == ChunkData.NO_STRIDE && terrainCache.containsChunkDataAtWorldPoint(message.getworldX(), message.getworldY(), message.getworldZ(), ChunkData.NO_STRIDE)){
//this is a full-res chunk, and we already had this chunk in cache //this is a full-res chunk, and we already had this chunk in cache
//need to flag foliage cell to update these positions given that we have changed terrain values //need to flag foliage cell to update these positions given that we have changed terrain values

View File

@ -1,5 +1,7 @@
package electrosphere.entity.types.common; package electrosphere.entity.types.common;
import java.util.stream.Collectors;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.ode4j.ode.DBody; import org.ode4j.ode.DBody;
@ -772,6 +774,13 @@ public class CommonEntityUtils {
public static Entity clientSpawnBasicObject(String type){ public static Entity clientSpawnBasicObject(String type){
CommonEntityType rawType = Globals.gameConfigCurrent.getObjectTypeMap().getType(type); CommonEntityType rawType = Globals.gameConfigCurrent.getObjectTypeMap().getType(type);
Entity rVal = EntityCreationUtils.createClientSpatialEntity(); Entity rVal = EntityCreationUtils.createClientSpatialEntity();
if(rawType == null){
String message = "Failed to lookup type: " + type + "\n" +
Globals.gameConfigCurrent.getObjectTypeMap().getTypes().stream().map((CommonEntityType typeObj) -> typeObj.getId()).collect(Collectors.toList()) +
"";
throw new Error(message);
}
// //
// //
//Common entity transforms //Common entity transforms

View File

@ -1,6 +1,8 @@
package electrosphere.net.client; package electrosphere.net.client;
import electrosphere.client.block.BlockChunkData; import electrosphere.client.block.BlockChunkData;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.client.terrain.data.TerrainChunkDataPool;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.mem.BlockChunkPool; import electrosphere.mem.BlockChunkPool;
@ -206,6 +208,56 @@ public class ClientNetworking implements Runnable {
buff.get(); buff.get();
} }
}); });
parser.registerCustomParser(TypeBytes.MESSAGE_TYPE_TERRAIN, TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA, (NetworkMessage message, ByteBuffer buff) -> {
TerrainMessage castMessage = (TerrainMessage)message;
//get meta data
castMessage.setworldX(buff.getInt());
castMessage.setworldY(buff.getInt());
castMessage.setworldZ(buff.getInt());
castMessage.setchunkResolution(buff.getInt());
castMessage.sethomogenousValue(buff.getInt());
//construct extra data
ChunkData chunk = TerrainChunkDataPool.getData();
chunk.setWorldX(castMessage.getworldX());
chunk.setWorldY(castMessage.getworldY());
chunk.setWorldZ(castMessage.getworldZ());
chunk.setStride(castMessage.getchunkResolution());
chunk.setHomogenousValue(castMessage.gethomogenousValue());
//get main data blob
if(castMessage.gethomogenousValue() == BlockChunkData.NOT_HOMOGENOUS){
for(int x = 0; x < ChunkData.CHUNK_DATA_SIZE; x++){
for(int z = 0; z < ChunkData.CHUNK_DATA_SIZE; z++){
for(int y = 0; y < ChunkData.CHUNK_DATA_SIZE; y++){
chunk.setWeight(x, y, z, buff.getFloat());
}
}
}
int firstType = -1;
boolean homogenous = true;
for(int x = 0; x < ChunkData.CHUNK_DATA_SIZE; x++){
for(int z = 0; z < ChunkData.CHUNK_DATA_SIZE; z++){
for(int y = 0; y < ChunkData.CHUNK_DATA_SIZE; y++){
int typeCurr = buff.getInt();
chunk.setType(x, y, z, typeCurr);
if(firstType == -1){
firstType = typeCurr;
} else if(homogenous && firstType == typeCurr){
homogenous = false;
}
}
}
}
} else {
buff.get();
}
//attach extra data
List<Object> extraData = new LinkedList<Object>();
extraData.add(chunk);
castMessage.setExtraData(extraData);
});

View File

@ -277,7 +277,12 @@ public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Spawn object " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Spawn object " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ());
//spawn item //spawn item
String objectType = message.getentitySubtype(); String objectType = message.getentitySubtype();
Entity newlySpawnedEntity = CommonEntityUtils.clientSpawnBasicObject(objectType); Entity newlySpawnedEntity = null;
try {
newlySpawnedEntity = CommonEntityUtils.clientSpawnBasicObject(objectType);
} catch (Error e){
throw new Error(message.getentityID() + " " + objectType, e);
}
//position //position
ClientEntityUtils.initiallyPositionEntity( ClientEntityUtils.initiallyPositionEntity(
newlySpawnedEntity, newlySpawnedEntity,

View File

@ -813,14 +813,12 @@ public class TerrainMessage extends NetworkMessage {
} }
TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE); TerrainMessage rVal = (TerrainMessage)pool.get(MessageType.TERRAIN_MESSAGE);
rVal.messageType = TerrainMessageType.SENDREDUCEDCHUNKDATA; rVal.messageType = TerrainMessageType.SENDREDUCEDCHUNKDATA;
rVal.setworldX(byteBuffer.getInt()); short pair = (short)((TypeBytes.MESSAGE_TYPE_TERRAIN << 4) & TypeBytes.TERRAIN_MESSAGE_TYPE_SENDREDUCEDCHUNKDATA);
rVal.setworldY(byteBuffer.getInt()); BiConsumer<NetworkMessage,ByteBuffer> customParser = customParserMap.get(pair);
rVal.setworldZ(byteBuffer.getInt()); if(customParser == null){
rVal.setchunkResolution(byteBuffer.getInt()); throw new Error("Custom parser undefined for message pair!");
rVal.sethomogenousValue(byteBuffer.getInt());
if(chunkDatalen > 0){
rVal.setchunkData(ByteStreamUtils.popByteArrayFromByteBuffer(byteBuffer, chunkDatalen));
} }
customParser.accept(rVal,byteBuffer);
return rVal; return rVal;
} }

View File

@ -1,7 +1,7 @@
package electrosphere.net.parser.net.raw; package electrosphere.net.parser.net.raw;
import electrosphere.net.parser.net.message.MessagePool; import electrosphere.net.parser.net.message.MessagePool;
import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.parser.net.message.NetworkMessage;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;

View File

@ -1,7 +1,7 @@
package electrosphere.net.parser.util; package electrosphere.net.parser.util;
import io.github.studiorailgun.CircularByteBuffer; import io.github.studiorailgun.CircularByteBuffer;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;

View File

@ -249,6 +249,7 @@
{ {
"messageName" : "SendReducedChunkData", "messageName" : "SendReducedChunkData",
"description" : "Sends chunk data to the client", "description" : "Sends chunk data to the client",
"customParser" : true,
"data" : [ "data" : [
"worldX", "worldX",
"worldY", "worldY",