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
#Sun Mar 17 09:54:23 EDT 2024
buildNumber=75
#Tue Mar 19 19:54:15 EDT 2024
buildNumber=77

View File

@ -41,6 +41,8 @@
## 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
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
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
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
Client Terrain Entity Management (specifically creation/teardown for client)
- Also queries for far out chunks to load far away terrain

View File

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

View File

@ -25,10 +25,6 @@ public class FluidChunkData {
float[][][] velocityY;
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
@ -43,43 +39,10 @@ public class FluidChunkData {
* @param voxelWeight The voxel weight array
*/
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
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
* @param localPosition The local position
@ -94,27 +57,7 @@ public class FluidChunkData {
* @return The weight of the specified voxel
*/
public float getWeight(int x, int y, int z){
return voxelWeight[z][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;
return voxelWeight[x][y][z];
}
/**

View File

@ -76,7 +76,7 @@ public class FluidCell {
fillInData();
modelEntity = FluidChunk.clientCreateFluidChunkEntity(data.getVoxelWeight());
modelEntity = FluidChunk.clientCreateFluidChunkEntity(weights);
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
}
@ -110,6 +110,9 @@ public class FluidCell {
* Fills in the internal arrays of data for generate terrain models
*/
private void fillInData(){
if(worldPos.x == 1 && worldPos.y == 0 && worldPos.z == 0){
System.out.println("aaaa");
}
//
//fill in data
//
@ -131,6 +134,12 @@ public class FluidCell {
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 {
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);
}
}
} 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 {
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);
}
}
} 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 {
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++){
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 {
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++){
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 {
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++){
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 {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
@ -222,15 +255,15 @@ public class FluidCell {
}
}
if(
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y + 1, worldPos.z + 1);
if(currentChunk != null){
if(currentChunk != null){
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 {
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = -1;

View File

@ -58,47 +58,24 @@ public class ClientFluidManager {
messageQueue.remove(message);
switch(message.getMessageSubtype()){
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());
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();
}
}
}
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);
FluidChunkData data = parseFluidDataBuffer(buffer);
fluidCache.addChunkDataToCache(
message.getworldX(), message.getworldY(), message.getworldZ(),
data
);
} 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:
LoggerInterface.loggerEngine.WARNING("ClientFluidManager: unhandled network message of type" + message.getMessageSubtype());
break;
@ -173,4 +150,51 @@ public class ClientFluidManager {
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(){
Globals.serverTerrainManager = ServerTerrainManager.constructArenaTerrainManager();
Globals.serverFluidManager = ServerFluidManager.constructArenaFluidManager();
Globals.serverFluidManager = ServerFluidManager.constructArenaFluidManager(Globals.serverTerrainManager);
}
private static void initServerArenaWorldData(){

View File

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

View File

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

View File

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

View File

@ -19,6 +19,7 @@ public class TerrainMessage extends NetworkMessage {
SENDCHUNKDATA,
REQUESTFLUIDDATA,
SENDFLUIDDATA,
UPDATEFLUIDDATA,
}
TerrainMessageType messageType;
@ -276,6 +277,8 @@ public class TerrainMessage extends NetworkMessage {
}
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA:
return TerrainMessage.canParsesendFluidDataMessage(byteBuffer);
case TypeBytes.TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA:
return TerrainMessage.canParseupdateFluidDataMessage(byteBuffer);
}
return false;
}
@ -564,6 +567,54 @@ public class TerrainMessage extends NetworkMessage {
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
void serialize(){
byte[] intValues = new byte[8];
@ -839,6 +890,32 @@ public class TerrainMessage extends NetworkMessage {
rawBytes[18+i] = chunkData[i];
}
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;
}

View File

@ -90,6 +90,7 @@ Message categories
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_SENDFLUIDDATA = 10;
public static final byte TERRAIN_MESSAGE_TYPE_UPDATEFLUIDDATA = 11;
/*
Terrain packet sizes
*/

View File

@ -45,6 +45,7 @@ public class TerrainProtocol {
);
} break;
//all ignored message types
case UPDATEFLUIDDATA:
case RESPONSEMETADATA:
case SPAWNPOSITION:
case UPDATEVOXEL:
@ -208,10 +209,54 @@ public class TerrainProtocol {
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.
//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.
@ -254,44 +299,7 @@ public class TerrainProtocol {
}
}
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());
return buffer;
}
}

View File

@ -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]
);
//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.net.parser.net.message.TerrainMessage;
import electrosphere.net.server.player.Player;
import electrosphere.net.server.protocol.TerrainProtocol;
import electrosphere.server.content.ServerContentManager;
import electrosphere.server.datacell.interfaces.DataCellManager;
import electrosphere.server.datacell.interfaces.VoxelCellManager;
@ -353,9 +354,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
loadedCellsLock.acquireUninterruptibly();
for(ServerDataCell cell : loadedCells){
Globals.microSimulation.simulate(cell, parent.getHitboxManager());
}
//simulate fluid
this.serverFluidManager.simulate();
Vector3i cellPos = this.getCellWorldPosition(cell);
boolean update = this.serverFluidManager.simulate(cellPos.x,cellPos.y,cellPos.z);
if(update){
rebroadcastFluidChunk(cellPos);
}
}
loadedCellsLock.release();
updatePlayerPositions();
}
@ -482,8 +488,23 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
}
@Override
/**
* Gets the fluid chunk at a given position
*/
public ServerFluidChunk getFluidChunkAtPosition(Vector3i worldPosition) {
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 y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
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;
}

View File

@ -6,6 +6,10 @@ import electrosphere.server.fluid.diskmap.FluidDiskMap;
import electrosphere.server.fluid.generation.ArenaFluidGenerator;
import electrosphere.server.fluid.generation.FluidGenerator;
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 java.nio.ByteBuffer;
import java.nio.FloatBuffer;
@ -49,17 +53,25 @@ public class ServerFluidManager {
//The generation algorithm for this fluid manager
FluidGenerator chunkGenerator;
//the fluid simulator
ServerFluidSimulator serverFluidSimulator;
//the terrain manager associated
ServerTerrainManager serverTerrainManager;
/**
* Constructor
*/
public ServerFluidManager(
ServerTerrainManager serverTerrainManager,
int worldSizeDiscrete,
int verticalInterpolationRatio,
float interpolationRandomDampener,
long seed,
FluidGenerator chunkGenerator
){
this.serverTerrainManager = serverTerrainManager;
this.worldSizeDiscrete = worldSizeDiscrete;
this.verticalInterpolationRatio = verticalInterpolationRatio;
this.chunkCache = new ConcurrentHashMap<String, ServerFluidChunk>();
@ -77,14 +89,16 @@ public class ServerFluidManager {
* Constructs an arena fluid manager
* @return The arena fluid manager
*/
public static ServerFluidManager constructArenaFluidManager(){
public static ServerFluidManager constructArenaFluidManager(ServerTerrainManager serverTerrainManager){
ServerFluidManager rVal = new ServerFluidManager();
rVal.serverTerrainManager = serverTerrainManager;
rVal.worldSizeDiscrete = 2;
rVal.verticalInterpolationRatio = 0;
rVal.chunkCache = new ConcurrentHashMap<String, ServerFluidChunk>();
rVal.chunkCacheContents = new CopyOnWriteArrayList<String>();
rVal.interpolationRandomDampener = 0.0f;
rVal.chunkGenerator = new ArenaFluidGenerator();
rVal.serverFluidSimulator = new FluidCellularAutomataSimulator();
return rVal;
}
@ -275,10 +289,15 @@ public class ServerFluidManager {
}
/**
* Simulates all active fluid chunks
* Simulates a chunk
*/
public void simulate(){
//TODO: implement
public boolean simulate(int worldX, int worldY, int worldZ){
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 weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DIMENSION; weightZ++){
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;
}
}
}
}