terrain streams without allocations
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
0d77c4e571
commit
c7cd9dfa34
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user