Compare commits

...

2 Commits

Author SHA1 Message Date
austin
db8ad7d10a Fix ghost water in the sky
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
2024-03-19 20:53:41 -04:00
austin
bfd7690403 fix fluid chunk model creating and flickering 2024-03-19 20:03:21 -04:00
23 changed files with 442 additions and 154 deletions

View File

@ -0,0 +1,5 @@
//courtesy https://stackoverflow.com/a/4275343
float rand(vec2 co){
return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
}

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file #maven.buildNumber.plugin properties file
#Sun Mar 17 09:54:23 EDT 2024 #Tue Mar 19 19:54:15 EDT 2024
buildNumber=75 buildNumber=77

View File

@ -41,6 +41,8 @@
## Ruins ## Ruins
## Light Valley
Valley with lights shooting around the sky from projectors placed sporadically around the valley, tie into lore and provide some kind of function (portal controller or something?)
@ -287,3 +289,17 @@ Plains with lots of fire
## Thunder Planes ## Thunder Planes
Constant Thunderstorms and lots of lightning strikes Constant Thunderstorms and lots of lightning strikes
# Sky Specific
## Sky Reefs
Full of kelp dangling from island, lots of sea-themed flying creatures

View File

@ -5,3 +5,8 @@
### "Black Hole" Zone ### "Black Hole" Zone
Zone with a big magical fire in the center or something like that. IE it's a huge pit and the zone you play in is around this pit. Zone with a big magical fire in the center or something like that. IE it's a huge pit and the zone you play in is around this pit.
### Solitairy Giant
Enclosed zone centered around a silent giant performing some toil (walking in circles around the periphery? Moving boulders? idk)
Ambient audio effect of him doing work the whole time

View File

@ -181,6 +181,17 @@ Fix Character creation preview not working
Clean up main method/class Clean up main method/class
Shader library system
- Abiltiy to include the shader library in individual files (ie implement #include)
Level loading/saving + Basic Editor
- Spin up voxel level (think arena mode)
- Save voxel level
- Basic editor functionality
- Menu of types of entities to spawn
- Button to spawn them at cursor
Transvoxel Algorithm Transvoxel Algorithm
Client Terrain Entity Management (specifically creation/teardown for client) Client Terrain Entity Management (specifically creation/teardown for client)
- Also queries for far out chunks to load far away terrain - Also queries for far out chunks to load far away terrain

View File

@ -201,6 +201,15 @@
"worldZ", "worldZ",
"chunkData" "chunkData"
] ]
},
{
"messageName" : "updateFluidData",
"data" : [
"worldX",
"worldY",
"worldZ",
"chunkData"
]
} }
] ]
} }

View File

@ -25,10 +25,6 @@ public class FluidChunkData {
float[][][] velocityY; float[][][] velocityY;
float[][][] velocityZ; float[][][] velocityZ;
//the list of positions modified since the last call to resetModifiedPositions
//Used in DrawCell to keep track of which positions to invalidate
Set<String> modifiedSinceLastGeneration = new HashSet<String>();
/** /**
* Gets the voxel weight array in this container * Gets the voxel weight array in this container
@ -43,43 +39,10 @@ public class FluidChunkData {
* @param voxelWeight The voxel weight array * @param voxelWeight The voxel weight array
*/ */
public void setVoxelWeight(float[][][] voxelWeight){ public void setVoxelWeight(float[][][] voxelWeight){
//mark changed cells
if(this.voxelWeight != null){
for(int x = 0; x < CHUNK_SIZE; x++){
for(int y = 0; y < CHUNK_SIZE; y++){
for(int z = 0; z < CHUNK_SIZE; z++){
if(voxelWeight[x][y][z] != this.voxelWeight[x][y][z]){
String key = getVoxelPositionKey(new Vector3i(x,y,z));
if(!modifiedSinceLastGeneration.contains(key)){
modifiedSinceLastGeneration.add(key);
}
}
}
}
}
}
//update data //update data
this.voxelWeight = voxelWeight; this.voxelWeight = voxelWeight;
} }
// /**
// * Updates the value of a single voxel in the chunk
// * @param localX The local position X
// * @param localY The local position Y
// * @param localZ The local position Z
// * @param weight The weight to set it to
// * @param type The type to set the voxel to
// */
// public void updatePosition(int localX, int localY, int localZ, float weight, int type){
// voxelWeight[localX][localY][localZ] = weight;
// voxelType[localX][localY][localZ] = type;
// //store as modified in cache
// String key = getVoxelPositionKey(new Vector3i(localX,localY,localZ));
// if(!modifiedSinceLastGeneration.contains(key)){
// modifiedSinceLastGeneration.add(key);
// }
// }
/** /**
* Gets the weight of a voxel at a poisiton * Gets the weight of a voxel at a poisiton
* @param localPosition The local position * @param localPosition The local position
@ -94,27 +57,7 @@ public class FluidChunkData {
* @return The weight of the specified voxel * @return The weight of the specified voxel
*/ */
public float getWeight(int x, int y, int z){ public float getWeight(int x, int y, int z){
return voxelWeight[z][y][z]; return voxelWeight[x][y][z];
}
/**
* Resets the cache of modified positions
*/
public void resetModifiedPositions(){
this.modifiedSinceLastGeneration.clear();
}
/**
* Gets the set of all modified positions since the last call to resetModifiedPositions
* @return The set of all modified positions
*/
public Set<Vector3i> getModifiedPositions(){
Set<Vector3i> rVal = new HashSet<Vector3i>();
for(String key : modifiedSinceLastGeneration){
String[] split = key.split("_");
rVal.add(new Vector3i(Integer.parseInt(split[0]),Integer.parseInt(split[1]),Integer.parseInt(split[2])));
}
return rVal;
} }
/** /**

View File

@ -65,7 +65,7 @@ public class FluidCell {
rVal.data = data; rVal.data = data;
return rVal; return rVal;
} }
/** /**
* Generates a drawable entity based on this chunk * Generates a drawable entity based on this chunk
*/ */
@ -76,7 +76,7 @@ public class FluidCell {
fillInData(); fillInData();
modelEntity = FluidChunk.clientCreateFluidChunkEntity(data.getVoxelWeight()); modelEntity = FluidChunk.clientCreateFluidChunkEntity(weights);
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos()); ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
} }
@ -110,6 +110,9 @@ public class FluidCell {
* Fills in the internal arrays of data for generate terrain models * Fills in the internal arrays of data for generate terrain models
*/ */
private void fillInData(){ private void fillInData(){
if(worldPos.x == 1 && worldPos.y == 0 && worldPos.z == 0){
System.out.println("aaaa");
}
// //
//fill in data //fill in data
// //
@ -131,6 +134,12 @@ public class FluidCell {
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][j] = currentChunk.getWeight(0, i, j); weights[ServerTerrainChunk.CHUNK_DIMENSION][i][j] = currentChunk.getWeight(0, i, j);
} }
} }
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][j] = -1;
}
}
} }
} else { } else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){ for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
@ -148,6 +157,12 @@ public class FluidCell {
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][j] = currentChunk.getWeight(i, 0, j); weights[i][ServerTerrainChunk.CHUNK_DIMENSION][j] = currentChunk.getWeight(i, 0, j);
} }
} }
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][j] = -1;
}
}
} }
} else { } else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){ for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
@ -165,6 +180,12 @@ public class FluidCell {
weights[i][j][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(i, j, 0); weights[i][j][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(i, j, 0);
} }
} }
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][j][ServerTerrainChunk.CHUNK_DIMENSION] = -1;
}
}
} }
} else { } else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){ for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
@ -183,6 +204,10 @@ public class FluidCell {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){ for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = currentChunk.getWeight(0, 0, i); weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = currentChunk.getWeight(0, 0, i);
} }
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = -1;
}
} }
} else { } else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){ for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
@ -199,6 +224,10 @@ public class FluidCell {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){ for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(0, i, 0); weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(0, i, 0);
} }
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = -1;
}
} }
} else { } else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){ for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
@ -215,6 +244,10 @@ public class FluidCell {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){ for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(i, 0, 0); weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(i, 0, 0);
} }
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = -1;
}
} }
} else { } else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){ for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
@ -222,15 +255,15 @@ public class FluidCell {
} }
} }
if( if(
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize() && worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize() && worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize() worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
){ ){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y + 1, worldPos.z + 1); currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y + 1, worldPos.z + 1);
if(currentChunk != null){ if(currentChunk != null){
if(currentChunk != null){ weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(0, 0, 0);
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(0, 0, 0); } else {
} weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = -1;
} }
} else { } else {
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = -1; weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = -1;

View File

@ -58,47 +58,24 @@ public class ClientFluidManager {
messageQueue.remove(message); messageQueue.remove(message);
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case SENDFLUIDDATA: { case SENDFLUIDDATA: {
float[][][] weights = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
float[][][] velocityX = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
float[][][] velocityY = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
float[][][] velocityZ = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
ByteBuffer buffer = ByteBuffer.wrap(message.getchunkData()); ByteBuffer buffer = ByteBuffer.wrap(message.getchunkData());
FloatBuffer floatBuffer = buffer.asFloatBuffer(); FluidChunkData data = parseFluidDataBuffer(buffer);
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
weights[x][y][z] = floatBuffer.get();
}
}
}
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
velocityX[x][y][z] = floatBuffer.get();
}
}
}
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
velocityY[x][y][z] = floatBuffer.get();
}
}
}
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
velocityZ[x][y][z] = floatBuffer.get();
}
}
}
FluidChunkData data = new FluidChunkData();
data.setVoxelWeight(weights);
fluidCache.addChunkDataToCache( fluidCache.addChunkDataToCache(
message.getworldX(), message.getworldY(), message.getworldZ(), message.getworldX(), message.getworldY(), message.getworldZ(),
data data
); );
} break; } break;
case UPDATEFLUIDDATA: {
ByteBuffer buffer = ByteBuffer.wrap(message.getchunkData());
FluidChunkData data = parseFluidDataBuffer(buffer);
fluidCache.addChunkDataToCache(
message.getworldX(), message.getworldY(), message.getworldZ(),
data
);
if(Globals.fluidCellManager != null){
Globals.fluidCellManager.markUpdateable(message.getworldX(), message.getworldY(), message.getworldZ());
}
} break;
default: default:
LoggerInterface.loggerEngine.WARNING("ClientFluidManager: unhandled network message of type" + message.getMessageSubtype()); LoggerInterface.loggerEngine.WARNING("ClientFluidManager: unhandled network message of type" + message.getMessageSubtype());
break; break;
@ -172,5 +149,52 @@ public class ClientFluidManager {
} }
fluidChunkGenerationQueue.clear(); fluidChunkGenerationQueue.clear();
} }
/**
* Parses a byte buffer into a fluid data object
* @param buffer the buffer
* @return the object
*/
private FluidChunkData parseFluidDataBuffer(ByteBuffer buffer){
float[][][] weights = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
float[][][] velocityX = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
float[][][] velocityY = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
float[][][] velocityZ = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
FloatBuffer floatBuffer = buffer.asFloatBuffer();
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
weights[x][y][z] = floatBuffer.get();
if(weights[x][y][z] <= 0){
weights[x][y][z] = -1f;
}
}
}
}
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
velocityX[x][y][z] = floatBuffer.get();
}
}
}
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
velocityY[x][y][z] = floatBuffer.get();
}
}
}
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
velocityZ[x][y][z] = floatBuffer.get();
}
}
}
FluidChunkData data = new FluidChunkData();
data.setVoxelWeight(weights);
return data;
}
} }

View File

@ -57,7 +57,7 @@ public class ArenaLoading {
private static void initServerArenaTerrainManager(){ private static void initServerArenaTerrainManager(){
Globals.serverTerrainManager = ServerTerrainManager.constructArenaTerrainManager(); Globals.serverTerrainManager = ServerTerrainManager.constructArenaTerrainManager();
Globals.serverFluidManager = ServerFluidManager.constructArenaFluidManager(); Globals.serverFluidManager = ServerFluidManager.constructArenaFluidManager(Globals.serverTerrainManager);
} }
private static void initServerArenaWorldData(){ private static void initServerArenaWorldData(){

View File

@ -30,6 +30,7 @@ public class FluidChunk {
rVal.putData(EntityDataStrings.FLUID_IS_FLUID, true); rVal.putData(EntityDataStrings.FLUID_IS_FLUID, true);
rVal.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true); rVal.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true);
rVal.removeData(EntityDataStrings.DRAW_SOLID_PASS);
return rVal; return rVal;
} }

View File

@ -53,6 +53,9 @@ public class TerrainProtocol {
case SENDFLUIDDATA: { case SENDFLUIDDATA: {
Globals.clientFluidManager.attachFluidMessage(message); Globals.clientFluidManager.attachFluidMessage(message);
} break; } break;
case UPDATEFLUIDDATA: {
Globals.clientFluidManager.attachFluidMessage(message);
} break;
default: default:
LoggerInterface.loggerNetworking.WARNING("Client networking: Unhandled message of type: " + message.getMessageSubtype()); LoggerInterface.loggerNetworking.WARNING("Client networking: Unhandled message of type: " + message.getMessageSubtype());
break; break;

View File

@ -246,6 +246,11 @@ SYNCHRONIZATION_MESSAGE,
rVal = TerrainMessage.parsesendFluidDataMessage(byteBuffer); rVal = TerrainMessage.parsesendFluidDataMessage(byteBuffer);
} }
break; break;
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA:
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
rVal = TerrainMessage.parseupdateFluidDataMessage(byteBuffer);
}
break;
} }
break; break;
case TypeBytes.MESSAGE_TYPE_SERVER: case TypeBytes.MESSAGE_TYPE_SERVER:

View File

@ -19,6 +19,7 @@ public class TerrainMessage extends NetworkMessage {
SENDCHUNKDATA, SENDCHUNKDATA,
REQUESTFLUIDDATA, REQUESTFLUIDDATA,
SENDFLUIDDATA, SENDFLUIDDATA,
UPDATEFLUIDDATA,
} }
TerrainMessageType messageType; TerrainMessageType messageType;
@ -276,6 +277,8 @@ public class TerrainMessage extends NetworkMessage {
} }
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA: case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA:
return TerrainMessage.canParsesendFluidDataMessage(byteBuffer); return TerrainMessage.canParsesendFluidDataMessage(byteBuffer);
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA:
return TerrainMessage.canParseupdateFluidDataMessage(byteBuffer);
} }
return false; return false;
} }
@ -564,6 +567,54 @@ public class TerrainMessage extends NetworkMessage {
return rVal; return rVal;
} }
public static boolean canParseupdateFluidDataMessage(CircularByteBuffer byteBuffer){
int currentStreamLength = byteBuffer.getRemaining();
List<Byte> temporaryByteQueue = new LinkedList();
if(currentStreamLength < 6){
return false;
}
if(currentStreamLength < 10){
return false;
}
if(currentStreamLength < 14){
return false;
}
int chunkDataSize = 0;
if(currentStreamLength < 18){
return false;
} else {
temporaryByteQueue.add(byteBuffer.peek(14 + 0));
temporaryByteQueue.add(byteBuffer.peek(14 + 1));
temporaryByteQueue.add(byteBuffer.peek(14 + 2));
temporaryByteQueue.add(byteBuffer.peek(14 + 3));
chunkDataSize = ByteStreamUtils.popIntFromByteQueue(temporaryByteQueue);
}
if(currentStreamLength < 18 + chunkDataSize){
return false;
}
return true;
}
public static TerrainMessage parseupdateFluidDataMessage(CircularByteBuffer byteBuffer){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEFLUIDDATA);
stripPacketHeader(byteBuffer);
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
rVal.setchunkData(ByteStreamUtils.popByteArrayFromByteQueue(byteBuffer));
return rVal;
}
public static TerrainMessage constructupdateFluidDataMessage(int worldX,int worldY,int worldZ,byte[] chunkData){
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATEFLUIDDATA);
rVal.setworldX(worldX);
rVal.setworldY(worldY);
rVal.setworldZ(worldZ);
rVal.setchunkData(chunkData);
rVal.serialize();
return rVal;
}
@Override @Override
void serialize(){ void serialize(){
byte[] intValues = new byte[8]; byte[] intValues = new byte[8];
@ -839,6 +890,32 @@ public class TerrainMessage extends NetworkMessage {
rawBytes[18+i] = chunkData[i]; rawBytes[18+i] = chunkData[i];
} }
break; break;
case UPDATEFLUIDDATA:
rawBytes = new byte[2+4+4+4+4+chunkData.length];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
//entity messaage header
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA;
intValues = ByteStreamUtils.serializeIntToBytes(worldX);
for(int i = 0; i < 4; i++){
rawBytes[2+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldY);
for(int i = 0; i < 4; i++){
rawBytes[6+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(worldZ);
for(int i = 0; i < 4; i++){
rawBytes[10+i] = intValues[i];
}
intValues = ByteStreamUtils.serializeIntToBytes(chunkData.length);
for(int i = 0; i < 4; i++){
rawBytes[14+i] = intValues[i];
}
for(int i = 0; i < chunkData.length; i++){
rawBytes[18+i] = chunkData[i];
}
break;
} }
serialized = true; serialized = true;
} }

View File

@ -90,6 +90,7 @@ Message categories
public static final byte TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA = 8; public static final byte TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA = 8;
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA = 9; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA = 9;
public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 10; public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 10;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 11;
/* /*
Terrain packet sizes Terrain packet sizes
*/ */

View File

@ -45,6 +45,7 @@ public class TerrainProtocol {
); );
} break; } break;
//all ignored message types //all ignored message types
case UPDATEFLUIDDATA:
case RESPONSEMETADATA: case RESPONSEMETADATA:
case SPAWNPOSITION: case SPAWNPOSITION:
case UPDATEVOXEL: case UPDATEVOXEL:
@ -207,11 +208,55 @@ public class TerrainProtocol {
// System.out.println("Received request for chunk " + message.getworldX() + " " + message.getworldY()); // System.out.println("Received request for chunk " + message.getworldX() + " " + message.getworldY());
ServerFluidChunk chunk = Globals.serverFluidManager.getChunk(worldX, worldY, worldZ); ServerFluidChunk chunk = Globals.serverFluidManager.getChunk(worldX, worldY, worldZ);
// float[][] macroValues = chunk.getMacroValues();//Globals.serverTerrainManager.getRad5MacroValues(message.getworldX(), message.getworldY());
// long[][] randomizer = chunk.getRandomizer();//Globals.serverTerrainManager.getRandomizer(message.getworldX(), message.getworldY());
ByteBuffer buffer = constructFluidByteBuffer(chunk);
connectionHandler.addMessagetoOutgoingQueue(TerrainMessage.constructsendFluidDataMessage(worldX, worldY, worldZ, buffer.array()));
}
static void sendWorldMetadata(ServerConnectionHandler connectionHandler){
//world metadata
connectionHandler.addMessagetoOutgoingQueue(
TerrainMessage.constructResponseMetadataMessage(
Globals.serverWorldData.getWorldSizeDiscrete(),
Globals.serverWorldData.getDynamicInterpolationRatio(),
Globals.serverWorldData.getRandomDampener(),
(int)Globals.serverWorldData.getWorldBoundMin().x,
(int)Globals.serverWorldData.getWorldBoundMin().z,
(int)Globals.serverWorldData.getWorldBoundMax().x,
(int)Globals.serverWorldData.getWorldBoundMax().z
)
);
}
/**
* Attempts to perform an edit requested by a client
* @param message The message containing the edit request
*/
static void attemptTerrainEdit(ServerConnectionHandler connectionHandler, TerrainMessage message){
Player player = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
}
/**
* Attempts to use an edit palette on the terrain
* @param connectionHandler The connection handler
* @param message The message that contains the request to use an edit palette
*/
static void attemptUseTerrainEditPalette(ServerConnectionHandler connectionHandler, TerrainMessage message){
Player player = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
Realm realm = Globals.realmManager.getPlayerRealm(player);
Vector3d location = new Vector3d(message.getrealLocationX(), message.getrealLocationY(), message.getrealLocationZ());
TerrainEditing.editTerrain(realm, location, message.getvalue(), message.getterrainValue(), message.getterrainWeight());
}
/**
* Constructs a buffer to send a fluid chunk to the client
* @param chunk The chunk to send
* @return the buffer
*/
public static ByteBuffer constructFluidByteBuffer(ServerFluidChunk chunk){
//The length along each access of the chunk data. Typically, should be at least 17. //The length along each access of the chunk data. Typically, should be at least 17.
//Because CHUNK_SIZE is 16, 17 adds the necessary extra value. Each chunk needs the value of the immediately following position to generate //Because CHUNK_SIZE is 16, 17 adds the necessary extra value. Each chunk needs the value of the immediately following position to generate
//chunk data that connects seamlessly to the next chunk. //chunk data that connects seamlessly to the next chunk.
@ -254,44 +299,7 @@ public class TerrainProtocol {
} }
} }
return buffer;
connectionHandler.addMessagetoOutgoingQueue(TerrainMessage.constructsendFluidDataMessage(worldX, worldY, worldZ, buffer.array()));
}
static void sendWorldMetadata(ServerConnectionHandler connectionHandler){
//world metadata
connectionHandler.addMessagetoOutgoingQueue(
TerrainMessage.constructResponseMetadataMessage(
Globals.serverWorldData.getWorldSizeDiscrete(),
Globals.serverWorldData.getDynamicInterpolationRatio(),
Globals.serverWorldData.getRandomDampener(),
(int)Globals.serverWorldData.getWorldBoundMin().x,
(int)Globals.serverWorldData.getWorldBoundMin().z,
(int)Globals.serverWorldData.getWorldBoundMax().x,
(int)Globals.serverWorldData.getWorldBoundMax().z
)
);
}
/**
* Attempts to perform an edit requested by a client
* @param message The message containing the edit request
*/
static void attemptTerrainEdit(ServerConnectionHandler connectionHandler, TerrainMessage message){
Player player = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
}
/**
* Attempts to use an edit palette on the terrain
* @param connectionHandler The connection handler
* @param message The message that contains the request to use an edit palette
*/
static void attemptUseTerrainEditPalette(ServerConnectionHandler connectionHandler, TerrainMessage message){
Player player = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
Realm realm = Globals.realmManager.getPlayerRealm(player);
Vector3d location = new Vector3d(message.getrealLocationX(), message.getrealLocationY(), message.getrealLocationZ());
TerrainEditing.editTerrain(realm, location, message.getvalue(), message.getterrainValue(), message.getterrainWeight());
} }
} }

View File

@ -588,7 +588,7 @@ public class FluidChunkModelGeneration {
List<Integer> faceElements = new LinkedList<Integer>(); List<Integer> faceElements = new LinkedList<Integer>();
//List of UVs //List of UVs
List<Float> UVs = new LinkedList<Float>(); List<Float> UVs = new LinkedList<Float>();
for(int x = 0; x < weightGrid.length - 1; x++){ for(int x = 0; x < weightGrid.length - 1; x++){
@ -602,7 +602,7 @@ public class FluidChunkModelGeneration {
weightGrid[x+0][y+1][z+0], weightGrid[x+0][y+1][z+1], weightGrid[x+1][y+1][z+1], weightGrid[x+1][y+1][z+0] weightGrid[x+0][y+1][z+0], weightGrid[x+0][y+1][z+1], weightGrid[x+1][y+1][z+1], weightGrid[x+1][y+1][z+0]
); );
//polygonize the current gridcell //polygonize the current gridcell
polygonize(currentCell, 0, triangles, vertMap, verts, normals, trianglesSharingVert); polygonize(currentCell, 0.0f, triangles, vertMap, verts, normals, trianglesSharingVert);
} }
} }
} }

View File

@ -17,6 +17,7 @@ import electrosphere.game.server.world.ServerWorldData;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.net.server.player.Player; import electrosphere.net.server.player.Player;
import electrosphere.net.server.protocol.TerrainProtocol;
import electrosphere.server.content.ServerContentManager; import electrosphere.server.content.ServerContentManager;
import electrosphere.server.datacell.interfaces.DataCellManager; import electrosphere.server.datacell.interfaces.DataCellManager;
import electrosphere.server.datacell.interfaces.VoxelCellManager; import electrosphere.server.datacell.interfaces.VoxelCellManager;
@ -353,9 +354,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
loadedCellsLock.acquireUninterruptibly(); loadedCellsLock.acquireUninterruptibly();
for(ServerDataCell cell : loadedCells){ for(ServerDataCell cell : loadedCells){
Globals.microSimulation.simulate(cell, parent.getHitboxManager()); Globals.microSimulation.simulate(cell, parent.getHitboxManager());
//simulate fluid
Vector3i cellPos = this.getCellWorldPosition(cell);
boolean update = this.serverFluidManager.simulate(cellPos.x,cellPos.y,cellPos.z);
if(update){
rebroadcastFluidChunk(cellPos);
}
} }
//simulate fluid
this.serverFluidManager.simulate();
loadedCellsLock.release(); loadedCellsLock.release();
updatePlayerPositions(); updatePlayerPositions();
} }
@ -482,8 +488,23 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
} }
@Override @Override
/**
* Gets the fluid chunk at a given position
*/
public ServerFluidChunk getFluidChunkAtPosition(Vector3i worldPosition) { public ServerFluidChunk getFluidChunkAtPosition(Vector3i worldPosition) {
return serverFluidManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z); return serverFluidManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z);
} }
/**
* Rebroadcasts the fluid cell at a given position
* @param worldPosition the world position
*/
private void rebroadcastFluidChunk(Vector3i worldPosition){
ServerDataCell cell = getCellAtWorldPosition(worldPosition);
ServerFluidChunk chunk = getFluidChunkAtPosition(worldPosition);
cell.broadcastNetworkMessage(
TerrainMessage.constructupdateFluidDataMessage(worldPosition.x, worldPosition.y, worldPosition.z, TerrainProtocol.constructFluidByteBuffer(chunk).array())
);
}
} }

View File

@ -17,12 +17,14 @@ public class ArenaFluidGenerator implements FluidGenerator {
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){ for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){ for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){ for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
weights[x][y][z] = -1.0f; weights[x][y][z] = 0f;
} }
} }
} }
weights[3][3][3] = 0.8f; if(worldX == 0 && worldY == 0 && worldZ == 0){
weights[7][5][7] = 1f;
}
return chunk; return chunk;
} }

View File

@ -6,6 +6,10 @@ import electrosphere.server.fluid.diskmap.FluidDiskMap;
import electrosphere.server.fluid.generation.ArenaFluidGenerator; import electrosphere.server.fluid.generation.ArenaFluidGenerator;
import electrosphere.server.fluid.generation.FluidGenerator; import electrosphere.server.fluid.generation.FluidGenerator;
import electrosphere.server.fluid.models.FluidModel; import electrosphere.server.fluid.models.FluidModel;
import electrosphere.server.fluid.simulator.ServerFluidSimulator;
import electrosphere.server.fluid.simulator.cellularautomata.FluidCellularAutomataSimulator;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.manager.ServerTerrainManager;
import electrosphere.util.FileUtils; import electrosphere.util.FileUtils;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.FloatBuffer; import java.nio.FloatBuffer;
@ -48,18 +52,26 @@ public class ServerFluidManager {
//The generation algorithm for this fluid manager //The generation algorithm for this fluid manager
FluidGenerator chunkGenerator; FluidGenerator chunkGenerator;
//the fluid simulator
ServerFluidSimulator serverFluidSimulator;
//the terrain manager associated
ServerTerrainManager serverTerrainManager;
/** /**
* Constructor * Constructor
*/ */
public ServerFluidManager( public ServerFluidManager(
ServerTerrainManager serverTerrainManager,
int worldSizeDiscrete, int worldSizeDiscrete,
int verticalInterpolationRatio, int verticalInterpolationRatio,
float interpolationRandomDampener, float interpolationRandomDampener,
long seed, long seed,
FluidGenerator chunkGenerator FluidGenerator chunkGenerator
){ ){
this.serverTerrainManager = serverTerrainManager;
this.worldSizeDiscrete = worldSizeDiscrete; this.worldSizeDiscrete = worldSizeDiscrete;
this.verticalInterpolationRatio = verticalInterpolationRatio; this.verticalInterpolationRatio = verticalInterpolationRatio;
this.chunkCache = new ConcurrentHashMap<String, ServerFluidChunk>(); this.chunkCache = new ConcurrentHashMap<String, ServerFluidChunk>();
@ -77,14 +89,16 @@ public class ServerFluidManager {
* Constructs an arena fluid manager * Constructs an arena fluid manager
* @return The arena fluid manager * @return The arena fluid manager
*/ */
public static ServerFluidManager constructArenaFluidManager(){ public static ServerFluidManager constructArenaFluidManager(ServerTerrainManager serverTerrainManager){
ServerFluidManager rVal = new ServerFluidManager(); ServerFluidManager rVal = new ServerFluidManager();
rVal.serverTerrainManager = serverTerrainManager;
rVal.worldSizeDiscrete = 2; rVal.worldSizeDiscrete = 2;
rVal.verticalInterpolationRatio = 0; rVal.verticalInterpolationRatio = 0;
rVal.chunkCache = new ConcurrentHashMap<String, ServerFluidChunk>(); rVal.chunkCache = new ConcurrentHashMap<String, ServerFluidChunk>();
rVal.chunkCacheContents = new CopyOnWriteArrayList<String>(); rVal.chunkCacheContents = new CopyOnWriteArrayList<String>();
rVal.interpolationRandomDampener = 0.0f; rVal.interpolationRandomDampener = 0.0f;
rVal.chunkGenerator = new ArenaFluidGenerator(); rVal.chunkGenerator = new ArenaFluidGenerator();
rVal.serverFluidSimulator = new FluidCellularAutomataSimulator();
return rVal; return rVal;
} }
@ -275,10 +289,15 @@ public class ServerFluidManager {
} }
/** /**
* Simulates all active fluid chunks * Simulates a chunk
*/ */
public void simulate(){ public boolean simulate(int worldX, int worldY, int worldZ){
//TODO: implement ServerFluidChunk fluidChunk = this.getChunk(worldX, worldY, worldZ);
ServerTerrainChunk terrainChunk = this.serverTerrainManager.getChunk(worldX, worldY, worldZ);
if(fluidChunk != null && terrainChunk != null && this.serverFluidSimulator != null){
return this.serverFluidSimulator.simulate(fluidChunk,terrainChunk,worldX,worldY,worldZ);
}
return false;
} }
} }

View File

@ -0,0 +1,22 @@
package electrosphere.server.fluid.simulator;
import electrosphere.server.fluid.manager.ServerFluidChunk;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
* A system capable of simulating a server fluid chunk for a single frame
*/
public interface ServerFluidSimulator {
/**
* Simulates the chunk for single step
* @param fluidChunk The fluid chunk
* @param terrainChunk The terrain chunk
* @param worldX the world x coordinate
* @param worldY the world y coordinate
* @param worldZ the world z coordinate
* @return True if the server data cell should update all players connected to it with new values, false otherwise
*/
public boolean simulate(ServerFluidChunk fluidChunk, ServerTerrainChunk terrainChunk, int worldX, int worldY, int worldZ);
}

View File

@ -0,0 +1,71 @@
package electrosphere.server.fluid.simulator.cellularautomata;
import electrosphere.server.fluid.manager.ServerFluidChunk;
import electrosphere.server.fluid.simulator.ServerFluidSimulator;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
* Simulates server fluid chunks via cellular automata
*/
public class FluidCellularAutomataSimulator implements ServerFluidSimulator {
static final float MAX_WEIGHT = 1.0f;
static final float GRAVITY_DIFF = 0.04f;
@Override
public boolean simulate(ServerFluidChunk fluidChunk, ServerTerrainChunk terrainChunk, int worldX, int worldY, int worldZ) {
float[][][] weights = fluidChunk.getWeights();
float[][][] terrainWeights = terrainChunk.getWeights();
//if true, alerts the server data cell to broadcast a new update message to all clients within it
boolean update = false;
if(worldX == 0 && worldY == 0 && worldZ == 0){
if(weights[8][3][8] < MAX_WEIGHT){
weights[8][3][8] = MAX_WEIGHT;
}
}
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
if(weights[x][y][z] <= 0){
continue;
} else {
if(y > 0 && weights[x][y-1][z] < MAX_WEIGHT){
update = true;
weights[x][y][z] -= GRAVITY_DIFF;
weights[x][y-1][z] += GRAVITY_DIFF;
} else {
//propagate sideways
int[] offsetX = new int[]{-1,1,0,0};
int[] offsetZ = new int[]{0,0,-1,1};
for(int i = 0; i < 4; i++){
int realX = x + offsetX[i];
int realZ = z + offsetZ[i];
if(realX > 0 && realX < ServerTerrainChunk.CHUNK_DIMENSION - 1 &&
realZ > 0 && realZ < ServerTerrainChunk.CHUNK_DIMENSION - 1
){
if(
weights[realX][y][realZ] < weights[x][y][z] &&
terrainWeights[realX][y][realZ] < MAX_WEIGHT
){
update = true;
weights[x][y][z] -= GRAVITY_DIFF;
weights[realX][y][realZ] += GRAVITY_DIFF;
}
}
}
}
}
}
}
}
return update;
}
}

View File

@ -27,7 +27,19 @@ public class ArenaChunkGenerator implements ChunkGenerator {
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DIMENSION; weightX++){ for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DIMENSION; weightX++){
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DIMENSION; weightZ++){ for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DIMENSION; weightZ++){
weights[weightX][0][weightZ] = 0.1f; weights[weightX][0][weightZ] = 0.1f;
values[weightX][0][weightZ] = 2; values[weightX][0][weightZ] = 1;
}
}
}
if(worldX == 0 && worldY == 0 && worldZ == 0){
for(int x = 5; x < 11; x++){
for(int z = 5; z < 11; z++){
if((x == 10 || x == 5 || z == 10 || z == 5)){
weights[x][0][z] = 1.0f;
weights[x][1][z] = 1.0f;
values[x][0][z] = 1;
values[x][1][z] = 1;
}
} }
} }
} }