more fluid dimensions work
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-11-30 17:25:26 -05:00
parent 40ae429417
commit 888cc254f3
7 changed files with 102 additions and 71 deletions

View File

@ -1197,6 +1197,7 @@ Fix viewport loading
Water spawner firing on repeat
Convert server side fluid storage to using buffers
Move cellular automata simulator package
Update fluid chunk dimensions to correspond with C code

View File

@ -3,7 +3,6 @@ package electrosphere.client.fluid.cache;
import org.joml.Vector3i;
import electrosphere.server.fluid.manager.ServerFluidChunk;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
* A container of data about a chunk of fluid
@ -13,7 +12,7 @@ public class FluidChunkData {
//The size of a chunk in virtual data
public static final int CHUNK_SIZE = ServerFluidChunk.BUFFER_DIM;
//The size of the data passed into marching cubes/transvoxel algorithm to get a fully connected and seamless chunk
public static final int CHUNK_DATA_GENERATOR_SIZE = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE;
public static final int CHUNK_DATA_GENERATOR_SIZE = ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE;
//How much of that fluid type is in this voxel
float[][][] voxelWeight;

View File

@ -13,7 +13,7 @@ import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.types.fluid.FluidChunk;
import electrosphere.renderer.shader.VisualShader;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.fluid.manager.ServerFluidChunk;
/**
*
@ -31,7 +31,7 @@ public class FluidCell {
DBody physicsObject;
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
float[][][] weights = new float[ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE][ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE][ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE];
//the value of an empty fluid cell weight that is not neighbored by a fluid value
public static final float ISO_SURFACE_EMPTY = -1;
@ -109,9 +109,9 @@ public class FluidCell {
//
//main chunk
FluidChunkData currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos);
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++){
for(int x = ServerFluidChunk.TRUE_DATA_OFFSET; x < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; x++){
for(int y = ServerFluidChunk.TRUE_DATA_OFFSET; y < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; y++){
for(int z = ServerFluidChunk.TRUE_DATA_OFFSET; z < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; z++){
weights[x][y][z] = currentChunk.getWeight(x,y,z);
}
}
@ -120,22 +120,22 @@ public class FluidCell {
if(worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize()){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y, worldPos.z);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][j] = currentChunk.getWeight(0, i, j);
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
for(int j = ServerFluidChunk.TRUE_DATA_OFFSET; j < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; j++){
weights[ServerFluidChunk.TRUE_DATA_DIM][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] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
for(int j = ServerFluidChunk.TRUE_DATA_OFFSET; j < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; j++){
weights[ServerFluidChunk.TRUE_DATA_DIM][i][j] = ISO_SURFACE_EMPTY;
}
}
}
} 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] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
for(int j = ServerFluidChunk.TRUE_DATA_OFFSET; j < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; j++){
weights[ServerFluidChunk.TRUE_DATA_DIM][i][j] = ISO_SURFACE_EMPTY;
}
}
}
@ -143,22 +143,22 @@ public class FluidCell {
if(worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize()){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y + 1, worldPos.z);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][j] = currentChunk.getWeight(i, 0, j);
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
for(int j = ServerFluidChunk.TRUE_DATA_OFFSET; j < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; j++){
weights[i][ServerFluidChunk.TRUE_DATA_DIM][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] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
for(int j = ServerFluidChunk.TRUE_DATA_OFFSET; j < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; j++){
weights[i][ServerFluidChunk.TRUE_DATA_DIM][j] = ISO_SURFACE_EMPTY;
}
}
}
} 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] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
for(int j = ServerFluidChunk.TRUE_DATA_OFFSET; j < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; j++){
weights[i][ServerFluidChunk.TRUE_DATA_DIM][j] = ISO_SURFACE_EMPTY;
}
}
}
@ -166,22 +166,22 @@ public class FluidCell {
if(worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z + 1);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
for(int j = 0; j < ServerTerrainChunk.CHUNK_DIMENSION; j++){
weights[i][j][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(i, j, 0);
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
for(int j = ServerFluidChunk.TRUE_DATA_OFFSET; j < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; j++){
weights[i][j][ServerFluidChunk.TRUE_DATA_DIM] = 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] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
for(int j = ServerFluidChunk.TRUE_DATA_OFFSET; j < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; j++){
weights[i][j][ServerFluidChunk.TRUE_DATA_DIM] = ISO_SURFACE_EMPTY;
}
}
}
} 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] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
for(int j = ServerFluidChunk.TRUE_DATA_OFFSET; j < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; j++){
weights[i][j][ServerFluidChunk.TRUE_DATA_DIM] = ISO_SURFACE_EMPTY;
}
}
}
@ -192,17 +192,17 @@ public class FluidCell {
){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y + 1, worldPos.z);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = currentChunk.getWeight(0, 0, i);
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
weights[ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM][i] = currentChunk.getWeight(0, 0, i);
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
weights[ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM][i] = ISO_SURFACE_EMPTY;
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
weights[ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM][i] = ISO_SURFACE_EMPTY;
}
}
//edge X-Z
@ -212,17 +212,17 @@ public class FluidCell {
){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y, worldPos.z + 1);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(0, i, 0);
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
weights[ServerFluidChunk.TRUE_DATA_DIM][i][ServerFluidChunk.TRUE_DATA_DIM] = currentChunk.getWeight(0, i, 0);
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
weights[ServerFluidChunk.TRUE_DATA_DIM][i][ServerFluidChunk.TRUE_DATA_DIM] = ISO_SURFACE_EMPTY;
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
weights[ServerFluidChunk.TRUE_DATA_DIM][i][ServerFluidChunk.TRUE_DATA_DIM] = ISO_SURFACE_EMPTY;
}
}
//edge Y-Z
@ -232,17 +232,17 @@ public class FluidCell {
){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y + 1, worldPos.z + 1);
if(currentChunk != null){
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(i, 0, 0);
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
weights[i][ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM] = currentChunk.getWeight(i, 0, 0);
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
weights[i][ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM] = ISO_SURFACE_EMPTY;
}
}
} else {
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
for(int i = ServerFluidChunk.TRUE_DATA_OFFSET; i < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; i++){
weights[i][ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM] = ISO_SURFACE_EMPTY;
}
}
if(
@ -252,12 +252,12 @@ public class FluidCell {
){
currentChunk = Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x + 1, worldPos.y + 1, worldPos.z + 1);
if(currentChunk != null){
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = currentChunk.getWeight(0, 0, 0);
weights[ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM] = currentChunk.getWeight(0, 0, 0);
} else {
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
weights[ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM] = ISO_SURFACE_EMPTY;
}
} else {
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = ISO_SURFACE_EMPTY;
weights[ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM][ServerFluidChunk.TRUE_DATA_DIM] = ISO_SURFACE_EMPTY;
}
//now set neighboring air weights based on nearby fluid count
@ -265,9 +265,9 @@ public class FluidCell {
int[] neighborIndexX = new int[]{-1,1,0,0,0,0};
int[] neighborIndexY = new int[]{0,0,-1,1,0,0};
int[] neighborIndexZ = new int[]{0,0,0,0,-1,1};
for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; z++){
for(int x = 0; x < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; x++){
for(int y = 0; y < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; y++){
for(int z = 0; z < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE; z++){
if(weights[x][y][z] > 0){
continue;
}
@ -276,9 +276,9 @@ public class FluidCell {
int currY = y + neighborIndexY[i];
int currZ = z + neighborIndexZ[i];
if(
currX >= 0 && currX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE &&
currY >= 0 && currY < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE &&
currZ >= 0 && currZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE &&
currX >= 0 && currX < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE &&
currY >= 0 && currY < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE &&
currZ >= 0 && currZ < ServerFluidChunk.TRUE_DATA_GENERATOR_SIZE &&
(1 + weights[x][y][z]) < weights[currX][currY][currZ]
){
weights[x][y][z] = -(1 - weights[currX][currY][currZ]);

View File

@ -28,9 +28,24 @@ public class ServerFluidChunk {
static final int CENTER_BUFF = 13;
/**
* Dimension of a fluid buffer
* Size of the true data. This is the data that is for this world position in particular
*/
public static final int BUFFER_DIM = 18;
public static final int TRUE_DATA_DIM = 16;
/**
* Size of the true data generator for meshing
*/
public static final int TRUE_DATA_GENERATOR_SIZE = TRUE_DATA_DIM + 1;
/**
* Number of positions to offset into the buffer before you will access the true data
*/
public static final int TRUE_DATA_OFFSET = 1;
/**
* Dimension of a fluid buffer. This includes positions that just store neighbor values
*/
public static final int BUFFER_DIM = TRUE_DATA_DIM + 2;
/**
* Size of a fluid buffer
@ -119,6 +134,11 @@ public class ServerFluidChunk {
*/
public int chunkMask;
/**
* Tracks whether this chunk was updated or not
*/
public boolean updated = false;
/**
* Constructor
* @param worldX The world x coordinate
@ -396,5 +416,12 @@ public class ServerFluidChunk {
return this.chunkMask;
}
/**
* Gets whether this chunk updated in its most recent frame or not
* @return true if it updated, false otherwise
*/
public boolean getUpdated(){
return updated;
}
}

View File

@ -60,7 +60,7 @@ public class ServerFluidManager {
ServerTerrainManager serverTerrainManager;
//controls whether fluid simulation should actually happen or not
boolean simulate = false;
boolean simulate = true;
@Exclude
/**

View File

@ -30,6 +30,11 @@ public class FluidAcceleratedSimulator implements ServerFluidSimulator {
@Override
public void simulate(List<ServerFluidChunk> fluidChunks, List<ServerFluidChunk> broadcastQueue){
FluidAcceleratedSimulator.simulate(fluidChunks, SIMULATE_TIMESTEP);
for(ServerFluidChunk fluidChunk : fluidChunks){
if(fluidChunk.getUpdated()){
broadcastQueue.add(fluidChunk);
}
}
}
/**

View File

@ -3,7 +3,6 @@ package electrosphere.server.fluid.simulator;
import java.util.List;
import electrosphere.server.fluid.manager.ServerFluidChunk;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
* Simulates server fluid chunks via cellular automata
@ -36,13 +35,13 @@ public class FluidCellularAutomataSimulator implements ServerFluidSimulator {
//if true, alerts the server data cell to broadcast a new update message to all clients within it
boolean update = false;
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++){
for(int x = ServerFluidChunk.TRUE_DATA_OFFSET; x < ServerFluidChunk.TRUE_DATA_DIM + ServerFluidChunk.TRUE_DATA_OFFSET; x++){
for(int y = ServerFluidChunk.TRUE_DATA_OFFSET; y < ServerFluidChunk.TRUE_DATA_DIM + ServerFluidChunk.TRUE_DATA_OFFSET; y++){
for(int z = ServerFluidChunk.TRUE_DATA_OFFSET; z < ServerFluidChunk.TRUE_DATA_DIM + ServerFluidChunk.TRUE_DATA_OFFSET; z++){
if(fluidChunk.getWeight(x, y, z) <= 0){
continue;
} else {
if(y > 0 && fluidChunk.getWeight(x, y - 1, z) < MAX_WEIGHT){
if(y > ServerFluidChunk.TRUE_DATA_OFFSET && fluidChunk.getWeight(x, y - 1, z) < MAX_WEIGHT){
update = true;
fluidChunk.setWeight(x, y, z, fluidChunk.getWeight(x, y, z) - GRAVITY_DIFF);
fluidChunk.setWeight(x, y - 1, z, fluidChunk.getWeight(x, y - 1, z) + GRAVITY_DIFF);
@ -53,8 +52,8 @@ public class FluidCellularAutomataSimulator implements ServerFluidSimulator {
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(realX > ServerFluidChunk.TRUE_DATA_OFFSET && realX < ServerFluidChunk.TRUE_DATA_DIM + ServerFluidChunk.TRUE_DATA_OFFSET - 1 &&
realZ > ServerFluidChunk.TRUE_DATA_OFFSET && realZ < ServerFluidChunk.TRUE_DATA_DIM + ServerFluidChunk.TRUE_DATA_OFFSET - 1
){
if(
fluidChunk.getWeight(realX, y, realZ) < fluidChunk.getWeight(x, y, z) &&