fluids are rendering albeit poorly
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
f328d16bab
commit
97edfacd41
208
assets/Shaders/fluid2/fluid2.fs
Normal file
208
assets/Shaders/fluid2/fluid2.fs
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
#define NR_POINT_LIGHTS 10
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
|
||||||
|
|
||||||
|
layout (std140) uniform Lights {
|
||||||
|
// this is how many because we have to align
|
||||||
|
// bytes it SHOULD in multiples of 16, this
|
||||||
|
// take it where it ACTUALLY is
|
||||||
|
//
|
||||||
|
//refer: https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
|
||||||
|
//
|
||||||
|
// base alignment aligned offset
|
||||||
|
//direct light
|
||||||
|
vec3 dLDirection; // 16 0
|
||||||
|
vec3 dLAmbient; // 16 16
|
||||||
|
vec3 dLDiffuse; // 16 32
|
||||||
|
vec3 dLSpecular; // 16 48
|
||||||
|
|
||||||
|
//point light
|
||||||
|
vec3 pLposition[NR_POINT_LIGHTS]; // 16*10 64
|
||||||
|
float pLconstant[NR_POINT_LIGHTS]; // 16*10 224
|
||||||
|
float pLlinear[NR_POINT_LIGHTS]; // 16*10 384
|
||||||
|
float pLquadratic[NR_POINT_LIGHTS]; // 16*10 544
|
||||||
|
vec3 pLambient[NR_POINT_LIGHTS]; // 16*10 704
|
||||||
|
vec3 pLdiffuse[NR_POINT_LIGHTS]; // 16*10 864
|
||||||
|
vec3 pLspecular[NR_POINT_LIGHTS]; // 16*10 1024
|
||||||
|
|
||||||
|
//for a total size of 1184
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Material {
|
||||||
|
sampler2D diffuse;
|
||||||
|
sampler2D specular;
|
||||||
|
float shininess;
|
||||||
|
};
|
||||||
|
|
||||||
|
in vec3 FragPos;
|
||||||
|
in vec3 Normal;
|
||||||
|
in vec2 texPlane1;
|
||||||
|
in vec2 texPlane2;
|
||||||
|
in vec2 texPlane3;
|
||||||
|
in vec4 FragPosLightSpace;
|
||||||
|
|
||||||
|
|
||||||
|
uniform vec3 viewPos;
|
||||||
|
// uniform DirLight dirLight;
|
||||||
|
// uniform PointLight pointLights[NR_POINT_LIGHTS];
|
||||||
|
// uniform SpotLight spotLight;
|
||||||
|
uniform Material material;
|
||||||
|
|
||||||
|
//texture stuff
|
||||||
|
// uniform sampler2D ourTexture;
|
||||||
|
uniform int hasTransparency;
|
||||||
|
// uniform sampler2D specularTexture;
|
||||||
|
|
||||||
|
//light depth map
|
||||||
|
uniform sampler2D shadowMap;
|
||||||
|
|
||||||
|
|
||||||
|
// function prototypes
|
||||||
|
// vec3 CalcDirLight(vec3 normal, vec3 viewDir);
|
||||||
|
// vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir);
|
||||||
|
// vec3 CalcSpotLight(vec3 normal, vec3 fragPos, vec3 viewDir);
|
||||||
|
float calcLightIntensityTotal(vec3 normal);
|
||||||
|
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal);
|
||||||
|
vec3 getColor(vec2 texPlane1, vec2 texPlane2, vec2 texPlane3, vec3 normal, Material material);
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec3 norm = normalize(Normal);
|
||||||
|
vec3 viewDir = normalize(viewPos - FragPos);
|
||||||
|
|
||||||
|
//grab light intensity
|
||||||
|
float lightIntensity = calcLightIntensityTotal(norm);
|
||||||
|
|
||||||
|
//get color of base texture
|
||||||
|
vec3 textureColor = getColor(texPlane1, texPlane2, texPlane3, norm, material);
|
||||||
|
|
||||||
|
//shadow
|
||||||
|
float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm);
|
||||||
|
|
||||||
|
//calculate final color
|
||||||
|
vec3 finalColor = textureColor * lightIntensity * max(shadow,0.4);
|
||||||
|
// vec3 lightAmount = CalcDirLight(norm, viewDir);
|
||||||
|
// for(int i = 0; i < NR_POINT_LIGHTS; i++){
|
||||||
|
// lightAmount += CalcPointLight(i, norm, FragPos, viewDir);
|
||||||
|
// }
|
||||||
|
|
||||||
|
//this final calculation is for transparency
|
||||||
|
FragColor = vec4(finalColor, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vec3 getColor(vec2 texPlane1, vec2 texPlane2, vec2 texPlane3, vec3 normal, Material material){
|
||||||
|
|
||||||
|
vec3 weights = abs(normal);
|
||||||
|
|
||||||
|
vec3 albedoX = texture(material.diffuse, texPlane1).rgb;
|
||||||
|
vec3 albedoY = texture(material.diffuse, texPlane2).rgb;
|
||||||
|
vec3 albedoZ = texture(material.diffuse, texPlane3).rgb;
|
||||||
|
|
||||||
|
|
||||||
|
return (albedoX * weights.x + albedoY * weights.y + albedoZ * weights.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
float calcLightIntensityAmbient(){
|
||||||
|
//calculate average of ambient light
|
||||||
|
float avg = (dLAmbient.x + dLAmbient.y + dLAmbient.z)/3.0;
|
||||||
|
return avg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
float calcLightIntensityDir(vec3 normal){
|
||||||
|
vec3 lightDir = normalize(-dLDirection);
|
||||||
|
// diffuse shading
|
||||||
|
float diff = max(dot(normal, lightDir), 0.0);
|
||||||
|
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
float calcLightIntensityTotal(vec3 normal){
|
||||||
|
//ambient intensity
|
||||||
|
float ambientLightIntensity = calcLightIntensityAmbient();
|
||||||
|
|
||||||
|
//get direct intensity
|
||||||
|
float directLightIntensity = calcLightIntensityDir(normal);
|
||||||
|
|
||||||
|
//sum
|
||||||
|
float total = ambientLightIntensity + directLightIntensity;
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
vec3 getTotalLightColor(vec3 normal){
|
||||||
|
//get the direct light color adjusted for intensity
|
||||||
|
vec3 diffuseLightColor = dLDiffuse * calcLightIntensityDir(normal);
|
||||||
|
|
||||||
|
//sum light colors
|
||||||
|
vec3 totalLightColor = diffuseLightColor;
|
||||||
|
return totalLightColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 CalcPointLight(int i, vec3 normal, vec3 fragPos, vec3 viewDir){
|
||||||
|
vec3 lightDir = normalize(pLposition[i] - fragPos);
|
||||||
|
// diffuse shading
|
||||||
|
float diff = max(dot(normal, lightDir), 0.0);
|
||||||
|
// specular shading
|
||||||
|
// vec3 reflectDir = reflect(-lightDir, normal);
|
||||||
|
// float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
|
||||||
|
// attenuation
|
||||||
|
float distance = length(pLposition[i] - fragPos);
|
||||||
|
float attenuation = 1.0 / (pLconstant[i] + pLlinear[i] * distance + pLquadratic[i] * (distance * distance));
|
||||||
|
// combine results
|
||||||
|
vec3 ambient = pLambient[i];
|
||||||
|
vec3 diffuse = pLdiffuse[i] * diff;
|
||||||
|
ambient *= attenuation;
|
||||||
|
diffuse *= attenuation;
|
||||||
|
// specular *= attenuation;
|
||||||
|
vec3 specular = vec3(0,0,0);
|
||||||
|
|
||||||
|
vec3 finalValue = (ambient + diffuse + specular);
|
||||||
|
finalValue = vec3(max(finalValue.x,0),max(finalValue.y,0),max(finalValue.z,0));
|
||||||
|
|
||||||
|
return finalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){
|
||||||
|
|
||||||
|
// perform perspective divide
|
||||||
|
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
|
||||||
|
|
||||||
|
//transform to NDC
|
||||||
|
projCoords = projCoords * 0.5 + 0.5;
|
||||||
|
|
||||||
|
//get closest depth from light's POV
|
||||||
|
float closestDepth = texture(shadowMap, projCoords.xy).r;
|
||||||
|
|
||||||
|
//get depth of current fragment
|
||||||
|
float currentDepth = projCoords.z;
|
||||||
|
|
||||||
|
//calculate bias
|
||||||
|
float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005);
|
||||||
|
|
||||||
|
//calculate shadow value
|
||||||
|
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0;
|
||||||
|
|
||||||
|
if(projCoords.z > 1.0){
|
||||||
|
shadow = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//calculate dot product, if it is >0 we know they're parallel-ish therefore should disregard the shadow mapping
|
||||||
|
//ie the fragment is already facing away from the light source
|
||||||
|
float dotprod = dot(normalize(lightDir),normalize(normal));
|
||||||
|
|
||||||
|
if(dotprod > 0.0){
|
||||||
|
shadow = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shadow = currentDepth;
|
||||||
|
|
||||||
|
return shadow;
|
||||||
|
}
|
||||||
62
assets/Shaders/fluid2/fluid2.vs
Normal file
62
assets/Shaders/fluid2/fluid2.vs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
//Vertex Shader
|
||||||
|
#version 330 core
|
||||||
|
|
||||||
|
//defines
|
||||||
|
#define TEXTURE_MAP_SCALE 3.0
|
||||||
|
|
||||||
|
|
||||||
|
//input buffers
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
layout (location = 1) in vec3 aNormal;
|
||||||
|
layout (location = 4) in vec2 aTex;
|
||||||
|
|
||||||
|
|
||||||
|
//coordinate space transformation matrices
|
||||||
|
uniform mat4 transform;
|
||||||
|
uniform mat4 model;
|
||||||
|
uniform mat4 view;
|
||||||
|
uniform mat4 projection;
|
||||||
|
uniform mat4 lightSpaceMatrix;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//output buffers
|
||||||
|
out vec3 Normal;
|
||||||
|
out vec3 FragPos;
|
||||||
|
out vec2 texPlane1;
|
||||||
|
out vec2 texPlane2;
|
||||||
|
out vec2 texPlane3;
|
||||||
|
out vec4 FragPosLightSpace;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
//normalize posiiton and normal
|
||||||
|
vec4 FinalVertex = vec4(aPos, 1.0);
|
||||||
|
vec4 FinalNormal = vec4(aNormal, 1.0);
|
||||||
|
|
||||||
|
|
||||||
|
//push frag, normal, and texture positions to fragment shader
|
||||||
|
FragPos = vec3(model * FinalVertex);
|
||||||
|
Normal = mat3(transpose(inverse(model))) * aNormal;
|
||||||
|
|
||||||
|
//reference https://catlikecoding.com/unity/tutorials/advanced-rendering/triplanar-mapping/
|
||||||
|
texPlane1 = aPos.zy * TEXTURE_MAP_SCALE;
|
||||||
|
texPlane2 = aPos.xz * TEXTURE_MAP_SCALE;
|
||||||
|
texPlane3 = aPos.xy * TEXTURE_MAP_SCALE;
|
||||||
|
|
||||||
|
//flip first coordinate if the normal is negative
|
||||||
|
//this minimizes texture flipping
|
||||||
|
texPlane1.x = texPlane1.x * sign(Normal.x);
|
||||||
|
texPlane2.x = texPlane2.x * sign(Normal.y);
|
||||||
|
texPlane3.x = texPlane3.x * sign(Normal.z);
|
||||||
|
|
||||||
|
|
||||||
|
//shadow map stuff
|
||||||
|
FragPosLightSpace = lightSpaceMatrix * vec4(FragPos, 1.0);
|
||||||
|
|
||||||
|
|
||||||
|
//set final position with opengl space
|
||||||
|
gl_Position = projection * view * model * FinalVertex;
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@
|
|||||||
```
|
```
|
||||||
generate 200 x 200
|
generate 200 x 200
|
||||||
interpolate x 20 in each direction
|
interpolate x 20 in each direction
|
||||||
this map will be 0.25 km resolution
|
this map will be 0.25 km resolution and ~62mb in size
|
||||||
Useful for macro sim
|
Useful for macro sim
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@ -196,6 +196,10 @@ Transvoxel Algorithm
|
|||||||
- Prebake all textures into atlas
|
- Prebake all textures into atlas
|
||||||
- Rewrite marching cubes shader to leverage this atlas
|
- Rewrite marching cubes shader to leverage this atlas
|
||||||
|
|
||||||
|
Another pass at grass
|
||||||
|
- Fix shader being camera position independent (if you move the wind moves with you lol)
|
||||||
|
- Multiple foliage models in same cell
|
||||||
|
|
||||||
Build a lod system
|
Build a lod system
|
||||||
- Could potentially be held at actor level
|
- Could potentially be held at actor level
|
||||||
- Link different models based on LOD level
|
- Link different models based on LOD level
|
||||||
|
|||||||
@ -184,6 +184,23 @@
|
|||||||
"worldZ",
|
"worldZ",
|
||||||
"chunkData"
|
"chunkData"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"messageName" : "RequestFluidData",
|
||||||
|
"data" : [
|
||||||
|
"worldX",
|
||||||
|
"worldY",
|
||||||
|
"worldZ"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"messageName" : "sendFluidData",
|
||||||
|
"data" : [
|
||||||
|
"worldX",
|
||||||
|
"worldY",
|
||||||
|
"worldZ",
|
||||||
|
"chunkData"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import electrosphere.entity.EntityUtils;
|
|||||||
import electrosphere.entity.Scene;
|
import electrosphere.entity.Scene;
|
||||||
import electrosphere.entity.types.attach.AttachUtils;
|
import electrosphere.entity.types.attach.AttachUtils;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public class ClientEntityCullingManager {
|
public class ClientEntityCullingManager {
|
||||||
|
|
||||||
Scene scene;
|
Scene scene;
|
||||||
@ -40,38 +41,4 @@ public class ClientEntityCullingManager {
|
|||||||
target.putData(EntityDataStrings.DATA_STRING_DRAW, true);
|
target.putData(EntityDataStrings.DATA_STRING_DRAW, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearOutOfBoundsEntities(){
|
|
||||||
if(Globals.commonWorldData != null && Globals.playerEntity != null && Globals.clientPlayerData != null){
|
|
||||||
Vector3d playerCharacterPos = EntityUtils.getPosition(Globals.playerEntity);
|
|
||||||
int playerCharacterWorldX = Globals.clientWorldData.convertRealToWorld(playerCharacterPos.x);
|
|
||||||
int playerCharacterWorldY = Globals.clientWorldData.convertRealToWorld(playerCharacterPos.y);
|
|
||||||
int playerCharacterWorldZ = Globals.clientWorldData.convertRealToWorld(playerCharacterPos.z);
|
|
||||||
if(
|
|
||||||
playerCharacterWorldX != Globals.clientPlayerData.getWorldPos().x||
|
|
||||||
playerCharacterWorldY != Globals.clientPlayerData.getWorldPos().y ||
|
|
||||||
playerCharacterWorldZ != Globals.clientPlayerData.getWorldPos().z
|
|
||||||
){
|
|
||||||
for(Entity entity : scene.getEntityList()){
|
|
||||||
if(entity.containsKey(EntityDataStrings.TERRAIN_IS_TERRAIN) || entity.containsKey(EntityDataStrings.ATTACH_PARENT) || entity.containsKey(EntityDataStrings.COLLISION_ENTITY_PARENT)){
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Vector3d position = EntityUtils.getPosition(entity);
|
|
||||||
//common world data is initialized with the collision data
|
|
||||||
//if this is null then the engine hasn't fully started up yet
|
|
||||||
if(position != null){
|
|
||||||
int worldX = Globals.clientWorldData.convertRealToWorld(position.x);
|
|
||||||
int worldZ = Globals.clientWorldData.convertRealToWorld(position.z);
|
|
||||||
if(!Globals.drawCellManager.coordsInPhysicsSpace(worldX, worldZ)){
|
|
||||||
//we need to just hide the entity
|
|
||||||
recursiveHide(entity);
|
|
||||||
} else {
|
|
||||||
//if the entity is within range and it's not set to visible, make it visible
|
|
||||||
recursiveShow(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,48 +17,19 @@ public class FluidChunkData {
|
|||||||
//The size of the data passed into marching cubes/transvoxel algorithm to get a fully connected and seamless chunk
|
//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 = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE;
|
||||||
|
|
||||||
//What type of fluid is in this voxel, eg stone vs dirt vs grass, etc
|
|
||||||
int[][][] voxelType;
|
|
||||||
//How much of that fluid type is in this voxel
|
//How much of that fluid type is in this voxel
|
||||||
float[][][] voxelWeight;
|
float[][][] voxelWeight;
|
||||||
|
|
||||||
|
//The velocities
|
||||||
|
float[][][] velocityX;
|
||||||
|
float[][][] velocityY;
|
||||||
|
float[][][] velocityZ;
|
||||||
|
|
||||||
//the list of positions modified since the last call to resetModifiedPositions
|
//the list of positions modified since the last call to resetModifiedPositions
|
||||||
//Used in DrawCell to keep track of which positions to invalidate
|
//Used in DrawCell to keep track of which positions to invalidate
|
||||||
Set<String> modifiedSinceLastGeneration = new HashSet<String>();
|
Set<String> modifiedSinceLastGeneration = new HashSet<String>();
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the voxel type array in this container
|
|
||||||
* @return The voxel type array
|
|
||||||
*/
|
|
||||||
public int[][][] getVoxelType(){
|
|
||||||
return voxelType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the voxel type array in this container
|
|
||||||
* @param voxelType The voxel type array
|
|
||||||
*/
|
|
||||||
public void setVoxelType(int[][][] voxelType){
|
|
||||||
//mark changed cells
|
|
||||||
if(this.voxelType != 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(voxelType[x][y][z] != this.voxelType[x][y][z]){
|
|
||||||
String key = getVoxelPositionKey(new Vector3i(x,y,z));
|
|
||||||
if(!modifiedSinceLastGeneration.contains(key)){
|
|
||||||
modifiedSinceLastGeneration.add(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//update data
|
|
||||||
this.voxelType = voxelType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the voxel weight array in this container
|
* Gets the voxel weight array in this container
|
||||||
* @return The voxel weight array
|
* @return The voxel weight array
|
||||||
@ -91,23 +62,23 @@ public class FluidChunkData {
|
|||||||
this.voxelWeight = voxelWeight;
|
this.voxelWeight = voxelWeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Updates the value of a single voxel in the chunk
|
// * Updates the value of a single voxel in the chunk
|
||||||
* @param localX The local position X
|
// * @param localX The local position X
|
||||||
* @param localY The local position Y
|
// * @param localY The local position Y
|
||||||
* @param localZ The local position Z
|
// * @param localZ The local position Z
|
||||||
* @param weight The weight to set it to
|
// * @param weight The weight to set it to
|
||||||
* @param type The type to set the voxel to
|
// * @param type The type to set the voxel to
|
||||||
*/
|
// */
|
||||||
public void updatePosition(int localX, int localY, int localZ, float weight, int type){
|
// public void updatePosition(int localX, int localY, int localZ, float weight, int type){
|
||||||
voxelWeight[localX][localY][localZ] = weight;
|
// voxelWeight[localX][localY][localZ] = weight;
|
||||||
voxelType[localX][localY][localZ] = type;
|
// voxelType[localX][localY][localZ] = type;
|
||||||
//store as modified in cache
|
// //store as modified in cache
|
||||||
String key = getVoxelPositionKey(new Vector3i(localX,localY,localZ));
|
// String key = getVoxelPositionKey(new Vector3i(localX,localY,localZ));
|
||||||
if(!modifiedSinceLastGeneration.contains(key)){
|
// if(!modifiedSinceLastGeneration.contains(key)){
|
||||||
modifiedSinceLastGeneration.add(key);
|
// modifiedSinceLastGeneration.add(key);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the weight of a voxel at a poisiton
|
* Gets the weight of a voxel at a poisiton
|
||||||
@ -119,12 +90,11 @@ public class FluidChunkData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type of a voxel at a position
|
* Gets the weight of a voxel at a poisiton
|
||||||
* @param localPosition The local position
|
* @return The weight of the specified voxel
|
||||||
* @return The type of the specified voxel
|
|
||||||
*/
|
*/
|
||||||
public int getType(Vector3i localPosition){
|
public float getWeight(int x, int y, int z){
|
||||||
return voxelType[localPosition.x][localPosition.y][localPosition.z];
|
return voxelWeight[z][y][z];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
240
src/main/java/electrosphere/client/fluid/cells/FluidCell.java
Normal file
240
src/main/java/electrosphere/client/fluid/cells/FluidCell.java
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
package electrosphere.client.fluid.cells;
|
||||||
|
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
import org.ode4j.ode.DBody;
|
||||||
|
|
||||||
|
import electrosphere.client.fluid.cache.FluidChunkData;
|
||||||
|
import electrosphere.collision.CollisionEngine;
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.entity.ClientEntityUtils;
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.entity.types.fluid.FluidChunk;
|
||||||
|
import electrosphere.renderer.shader.ShaderProgram;
|
||||||
|
import electrosphere.renderer.texture.Texture;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author satellite
|
||||||
|
*/
|
||||||
|
public class FluidCell {
|
||||||
|
//the position of the draw cell in world coordinates
|
||||||
|
Vector3i worldPos;
|
||||||
|
|
||||||
|
FluidChunkData data;
|
||||||
|
|
||||||
|
Entity modelEntity;
|
||||||
|
|
||||||
|
ShaderProgram program;
|
||||||
|
|
||||||
|
DBody physicsObject;
|
||||||
|
|
||||||
|
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
|
||||||
|
|
||||||
|
static Texture groundTextureOne = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
static Texture groundTextureTwo = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
static Texture groundTextureThree = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
static Texture groundTextureFour = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
|
||||||
|
static {
|
||||||
|
// groundTextureOne = new Texture("/Textures/Ground/GrassTileable.png");
|
||||||
|
// groundTextureTwo = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
// groundTextureThree = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
// groundTextureFour = new Texture("/Textures/Ground/Dirt1.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FluidCell(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a drawcell object
|
||||||
|
*/
|
||||||
|
public static FluidCell generateFluidCell(
|
||||||
|
Vector3i worldPos,
|
||||||
|
FluidChunkData data,
|
||||||
|
ShaderProgram program
|
||||||
|
){
|
||||||
|
FluidCell rVal = new FluidCell();
|
||||||
|
rVal.worldPos = worldPos;
|
||||||
|
rVal.program = program;
|
||||||
|
rVal.data = data;
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a drawable entity based on this chunk
|
||||||
|
*/
|
||||||
|
public void generateDrawableEntity(){
|
||||||
|
if(modelEntity != null){
|
||||||
|
Globals.clientScene.deregisterEntity(modelEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
fillInData();
|
||||||
|
|
||||||
|
modelEntity = FluidChunk.clientCreateFluidChunkEntity(data.getVoxelWeight());
|
||||||
|
|
||||||
|
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Vector3d getRealPos(){
|
||||||
|
return new Vector3d(
|
||||||
|
worldPos.x * FluidChunkData.CHUNK_SIZE,
|
||||||
|
worldPos.y * FluidChunkData.CHUNK_SIZE,
|
||||||
|
worldPos.z * FluidChunkData.CHUNK_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys a drawcell including its physics
|
||||||
|
*/
|
||||||
|
public void destroy(){
|
||||||
|
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
|
||||||
|
collisionEngine.destroyEntityThatHasPhysics(modelEntity);
|
||||||
|
EntityUtils.cleanUpEntity(modelEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the current chunk data for this draw cell
|
||||||
|
* @return The chunk data
|
||||||
|
*/
|
||||||
|
public FluidChunkData getData(){
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills in the internal arrays of data for generate terrain models
|
||||||
|
*/
|
||||||
|
private void fillInData(){
|
||||||
|
//
|
||||||
|
//fill in data
|
||||||
|
//
|
||||||
|
//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++){
|
||||||
|
weights[x][y][z] = currentChunk.getWeight(x,y,z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//face X
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//face Y
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//face Z
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//edge X-Y
|
||||||
|
if(
|
||||||
|
worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize()
|
||||||
|
){
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
|
||||||
|
weights[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//edge X-Z
|
||||||
|
if(
|
||||||
|
worldPos.x + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
|
||||||
|
){
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
|
||||||
|
weights[ServerTerrainChunk.CHUNK_DIMENSION][i][ServerTerrainChunk.CHUNK_DIMENSION] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//edge Y-Z
|
||||||
|
if(
|
||||||
|
worldPos.y + 1 < Globals.clientWorldData.getWorldDiscreteSize() &&
|
||||||
|
worldPos.z + 1 < Globals.clientWorldData.getWorldDiscreteSize()
|
||||||
|
){
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for(int i = 0; i < ServerTerrainChunk.CHUNK_DIMENSION; i++){
|
||||||
|
weights[i][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(
|
||||||
|
worldPos.z + 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@ import electrosphere.renderer.shader.ShaderProgram;
|
|||||||
*
|
*
|
||||||
* @author satellite
|
* @author satellite
|
||||||
*/
|
*/
|
||||||
public class FluidDrawCellManager {
|
public class FluidCellManager {
|
||||||
|
|
||||||
|
|
||||||
//the center of this cell manager's array in cell space
|
//the center of this cell manager's array in cell space
|
||||||
@ -35,8 +35,8 @@ public class FluidDrawCellManager {
|
|||||||
int miniCellWidth;
|
int miniCellWidth;
|
||||||
|
|
||||||
//all currently displaying mini cells
|
//all currently displaying mini cells
|
||||||
Set<FluidDrawCell> cells;
|
Set<FluidCell> cells;
|
||||||
Map<String,FluidDrawCell> keyCellMap = new HashMap<String,FluidDrawCell>();
|
Map<String,FluidCell> keyCellMap = new HashMap<String,FluidCell>();
|
||||||
Set<String> hasNotRequested;
|
Set<String> hasNotRequested;
|
||||||
Set<String> hasRequested;
|
Set<String> hasRequested;
|
||||||
Set<String> drawable;
|
Set<String> drawable;
|
||||||
@ -59,8 +59,6 @@ public class FluidDrawCellManager {
|
|||||||
int worldBoundDiscreteMin = 0;
|
int worldBoundDiscreteMin = 0;
|
||||||
int worldBoundDiscreteMax = 0;
|
int worldBoundDiscreteMax = 0;
|
||||||
|
|
||||||
//client terrain manager
|
|
||||||
// ClientTerrainManager clientTerrainManager;
|
|
||||||
|
|
||||||
|
|
||||||
//ready to start updating?
|
//ready to start updating?
|
||||||
@ -78,9 +76,9 @@ public class FluidDrawCellManager {
|
|||||||
* @param discreteX The initial discrete position X coordinate
|
* @param discreteX The initial discrete position X coordinate
|
||||||
* @param discreteY The initial discrete position Y coordinate
|
* @param discreteY The initial discrete position Y coordinate
|
||||||
*/
|
*/
|
||||||
public FluidDrawCellManager(ClientTerrainManager clientTerrainManager, int discreteX, int discreteY, int discreteZ){
|
public FluidCellManager(ClientTerrainManager clientTerrainManager, int discreteX, int discreteY, int discreteZ){
|
||||||
worldBoundDiscreteMax = (int)(Globals.clientWorldData.getWorldBoundMin().x / Globals.clientWorldData.getDynamicInterpolationRatio() * 1.0f);
|
worldBoundDiscreteMax = (int)(Globals.clientWorldData.getWorldBoundMin().x / Globals.clientWorldData.getDynamicInterpolationRatio() * 1.0f);
|
||||||
cells = new HashSet<FluidDrawCell>();
|
cells = new HashSet<FluidCell>();
|
||||||
hasNotRequested = new HashSet<String>();
|
hasNotRequested = new HashSet<String>();
|
||||||
drawable = new HashSet<String>();
|
drawable = new HashSet<String>();
|
||||||
undrawable = new HashSet<String>();
|
undrawable = new HashSet<String>();
|
||||||
@ -102,7 +100,7 @@ public class FluidDrawCellManager {
|
|||||||
update = true;
|
update = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FluidDrawCellManager(){
|
FluidCellManager(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +130,7 @@ public class FluidDrawCellManager {
|
|||||||
){
|
){
|
||||||
// if(!hasRequested.contains(targetKey)){
|
// if(!hasRequested.contains(targetKey)){
|
||||||
//client should request chunk data from server
|
//client should request chunk data from server
|
||||||
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestChunkDataMessage(
|
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestFluidDataMessage(
|
||||||
worldPos.x,
|
worldPos.x,
|
||||||
worldPos.y,
|
worldPos.y,
|
||||||
worldPos.z
|
worldPos.z
|
||||||
@ -161,7 +159,7 @@ public class FluidDrawCellManager {
|
|||||||
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
|
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
|
||||||
){
|
){
|
||||||
if(containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z)){
|
if(containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z)){
|
||||||
FluidDrawCell cell = FluidDrawCell.generateFluidCell(
|
FluidCell cell = FluidCell.generateFluidCell(
|
||||||
worldPos,
|
worldPos,
|
||||||
Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z),
|
Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z),
|
||||||
program
|
program
|
||||||
@ -256,14 +254,14 @@ public class FluidDrawCellManager {
|
|||||||
* Clears all cells outside of draw radius
|
* Clears all cells outside of draw radius
|
||||||
*/
|
*/
|
||||||
private void clearOutOfBoundsCells(){
|
private void clearOutOfBoundsCells(){
|
||||||
Set<FluidDrawCell> cellsToRemove = new HashSet<FluidDrawCell>();
|
Set<FluidCell> cellsToRemove = new HashSet<FluidCell>();
|
||||||
for(FluidDrawCell cell : cells){
|
for(FluidCell cell : cells){
|
||||||
Vector3d realPos = cell.getRealPos();
|
Vector3d realPos = cell.getRealPos();
|
||||||
if(Globals.playerEntity != null && EntityUtils.getPosition(Globals.playerEntity).distance(realPos) > drawRadius){
|
if(Globals.playerEntity != null && EntityUtils.getPosition(Globals.playerEntity).distance(realPos) > drawRadius){
|
||||||
cellsToRemove.add(cell);
|
cellsToRemove.add(cell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for(FluidDrawCell cell : cellsToRemove){
|
for(FluidCell cell : cellsToRemove){
|
||||||
cells.remove(cell);
|
cells.remove(cell);
|
||||||
String key = getCellKey(cell.worldPos.x, cell.worldPos.y, cell.worldPos.z);
|
String key = getCellKey(cell.worldPos.x, cell.worldPos.y, cell.worldPos.z);
|
||||||
hasNotRequested.remove(key);
|
hasNotRequested.remove(key);
|
||||||
@ -358,8 +356,8 @@ public class FluidDrawCellManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
|
boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
|
||||||
if(Globals.clientTerrainManager != null){
|
if(Globals.clientFluidManager != null){
|
||||||
return Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldX,worldY,worldZ);
|
return Globals.clientFluidManager.containsChunkDataAtWorldPoint(worldX,worldY,worldZ);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1,103 +0,0 @@
|
|||||||
package electrosphere.client.fluid.cells;
|
|
||||||
|
|
||||||
import org.joml.Vector3d;
|
|
||||||
import org.joml.Vector3i;
|
|
||||||
import org.ode4j.ode.DBody;
|
|
||||||
|
|
||||||
import electrosphere.client.fluid.cache.FluidChunkData;
|
|
||||||
import electrosphere.collision.CollisionEngine;
|
|
||||||
import electrosphere.engine.Globals;
|
|
||||||
import electrosphere.entity.ClientEntityUtils;
|
|
||||||
import electrosphere.entity.Entity;
|
|
||||||
import electrosphere.entity.EntityUtils;
|
|
||||||
import electrosphere.entity.types.fluid.FluidChunk;
|
|
||||||
import electrosphere.renderer.shader.ShaderProgram;
|
|
||||||
import electrosphere.renderer.texture.Texture;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author satellite
|
|
||||||
*/
|
|
||||||
public class FluidDrawCell {
|
|
||||||
//the position of the draw cell in world coordinates
|
|
||||||
Vector3i worldPos;
|
|
||||||
|
|
||||||
FluidChunkData data;
|
|
||||||
|
|
||||||
Entity modelEntity;
|
|
||||||
|
|
||||||
ShaderProgram program;
|
|
||||||
|
|
||||||
DBody physicsObject;
|
|
||||||
|
|
||||||
static Texture groundTextureOne = new Texture("/Textures/Ground/Dirt1.png");
|
|
||||||
static Texture groundTextureTwo = new Texture("/Textures/Ground/Dirt1.png");
|
|
||||||
static Texture groundTextureThree = new Texture("/Textures/Ground/Dirt1.png");
|
|
||||||
static Texture groundTextureFour = new Texture("/Textures/Ground/Dirt1.png");
|
|
||||||
|
|
||||||
static {
|
|
||||||
// groundTextureOne = new Texture("/Textures/Ground/GrassTileable.png");
|
|
||||||
// groundTextureTwo = new Texture("/Textures/Ground/Dirt1.png");
|
|
||||||
// groundTextureThree = new Texture("/Textures/Ground/Dirt1.png");
|
|
||||||
// groundTextureFour = new Texture("/Textures/Ground/Dirt1.png");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FluidDrawCell(){
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a drawcell object
|
|
||||||
*/
|
|
||||||
public static FluidDrawCell generateFluidCell(
|
|
||||||
Vector3i worldPos,
|
|
||||||
FluidChunkData data,
|
|
||||||
ShaderProgram program
|
|
||||||
){
|
|
||||||
FluidDrawCell rVal = new FluidDrawCell();
|
|
||||||
rVal.worldPos = worldPos;
|
|
||||||
rVal.program = program;
|
|
||||||
rVal.data = data;
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates a drawable entity based on this chunk
|
|
||||||
*/
|
|
||||||
public void generateDrawableEntity(){
|
|
||||||
if(modelEntity != null){
|
|
||||||
Globals.clientScene.deregisterEntity(modelEntity);
|
|
||||||
}
|
|
||||||
modelEntity = FluidChunk.clientCreateFluidChunkEntity(data.getVoxelWeight(), data.getVoxelType());
|
|
||||||
|
|
||||||
ClientEntityUtils.initiallyPositionEntity(modelEntity, getRealPos());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Vector3d getRealPos(){
|
|
||||||
return new Vector3d(
|
|
||||||
worldPos.x * FluidChunkData.CHUNK_SIZE,
|
|
||||||
worldPos.y * FluidChunkData.CHUNK_SIZE,
|
|
||||||
worldPos.z * FluidChunkData.CHUNK_SIZE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys a drawcell including its physics
|
|
||||||
*/
|
|
||||||
public void destroy(){
|
|
||||||
CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
|
|
||||||
collisionEngine.destroyEntityThatHasPhysics(modelEntity);
|
|
||||||
EntityUtils.cleanUpEntity(modelEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current chunk data for this draw cell
|
|
||||||
* @return The chunk data
|
|
||||||
*/
|
|
||||||
public FluidChunkData getData(){
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -57,29 +57,42 @@ public class ClientFluidManager {
|
|||||||
for(TerrainMessage message : messageQueue){
|
for(TerrainMessage message : messageQueue){
|
||||||
messageQueue.remove(message);
|
messageQueue.remove(message);
|
||||||
switch(message.getMessageSubtype()){
|
switch(message.getMessageSubtype()){
|
||||||
case SENDCHUNKDATA: {
|
case SENDFLUIDDATA: {
|
||||||
int[][][] values = new int[FluidChunkData.CHUNK_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_SIZE];
|
float[][][] weights = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
|
||||||
float[][][] weights = new float[FluidChunkData.CHUNK_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_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();
|
FloatBuffer floatBuffer = buffer.asFloatBuffer();
|
||||||
for(int x = 0; x < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){
|
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
|
||||||
for(int y = 0; y < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){
|
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
|
||||||
for(int z = 0; z < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){
|
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
|
||||||
weights[x][y][z] = floatBuffer.get();
|
weights[x][y][z] = floatBuffer.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IntBuffer intView = buffer.asIntBuffer();
|
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
|
||||||
intView.position(floatBuffer.position());
|
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
|
||||||
for(int x = 0; x < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){
|
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
|
||||||
for(int y = 0; y < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){
|
velocityX[x][y][z] = floatBuffer.get();
|
||||||
for(int z = 0; z < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){
|
}
|
||||||
values[x][y][z] = intView.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();
|
FluidChunkData data = new FluidChunkData();
|
||||||
data.setVoxelType(values);
|
|
||||||
data.setVoxelWeight(weights);
|
data.setVoxelWeight(weights);
|
||||||
fluidCache.addChunkDataToCache(
|
fluidCache.addChunkDataToCache(
|
||||||
message.getworldX(), message.getworldY(), message.getworldZ(),
|
message.getworldX(), message.getworldY(), message.getworldZ(),
|
||||||
@ -96,7 +109,7 @@ public class ClientFluidManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void attachTerrainMessage(TerrainMessage message){
|
public void attachFluidMessage(TerrainMessage message){
|
||||||
messageQueue.add(message);
|
messageQueue.add(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -311,7 +311,6 @@ public class ClientFoliageManager {
|
|||||||
* @param voxelPos The voxel position
|
* @param voxelPos The voxel position
|
||||||
*/
|
*/
|
||||||
private void createFoliageCell(Vector3i worldPos, Vector3i voxelPos, float initialGrowthLevel){
|
private void createFoliageCell(Vector3i worldPos, Vector3i voxelPos, float initialGrowthLevel){
|
||||||
System.out.println("Create foliage cell");
|
|
||||||
//get foliage types supported
|
//get foliage types supported
|
||||||
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||||
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPos)).getAmbientFoliage();
|
List<String> foliageTypesSupported = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(data.getType(voxelPos)).getAmbientFoliage();
|
||||||
@ -350,11 +349,6 @@ public class ClientFoliageManager {
|
|||||||
float height_20 = (float)(sample_20 != null ? sample_20.y : height_11);
|
float height_20 = (float)(sample_20 != null ? sample_20.y : height_11);
|
||||||
float height_21 = (float)(sample_21 != null ? sample_21.y : height_11);
|
float height_21 = (float)(sample_21 != null ? sample_21.y : height_11);
|
||||||
float height_22 = (float)(sample_22 != null ? sample_22.y : height_11);
|
float height_22 = (float)(sample_22 != null ? sample_22.y : height_11);
|
||||||
if(worldPos.x == 0 && worldPos.z == 0 && voxelPos.x < 5 && voxelPos.z < 5){
|
|
||||||
System.out.println(voxelPos);
|
|
||||||
System.out.println(height_11);
|
|
||||||
System.out.println(realPos);
|
|
||||||
}
|
|
||||||
//each height is in real world coordinates that are absolute
|
//each height is in real world coordinates that are absolute
|
||||||
//when rendering, there's already a y offset for the center of the field of grass (based on the model matrix)
|
//when rendering, there's already a y offset for the center of the field of grass (based on the model matrix)
|
||||||
//so when offseting the position of the blade of grass RELATIVE to the overall instance being drawn, need to subtract the real world coordinates of the overall instance
|
//so when offseting the position of the blade of grass RELATIVE to the overall instance being drawn, need to subtract the real world coordinates of the overall instance
|
||||||
@ -375,15 +369,6 @@ public class ClientFoliageManager {
|
|||||||
double offsetZ = relativePositionOnGridZ;
|
double offsetZ = relativePositionOnGridZ;
|
||||||
//determine quadrant we're placing in
|
//determine quadrant we're placing in
|
||||||
double offsetY = 0;
|
double offsetY = 0;
|
||||||
if(worldPos.x == 0 && worldPos.z == 0 && voxelPos.x < 5 && voxelPos.z < 5 && x == 26 && z == 26){
|
|
||||||
offsetY =
|
|
||||||
height_11 * (1-relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
|
||||||
height_12 * (1-relativePositionOnGridX) * ( relativePositionOnGridZ) +
|
|
||||||
height_21 * ( relativePositionOnGridX) * (1-relativePositionOnGridZ) +
|
|
||||||
height_22 * ( relativePositionOnGridX) * ( relativePositionOnGridZ);
|
|
||||||
System.out.println(offsetY);
|
|
||||||
System.out.println((float)offsetY - (float)realPos.y);
|
|
||||||
}
|
|
||||||
boolean addBlade = false;
|
boolean addBlade = false;
|
||||||
if(relativePositionOnGridX >=0){
|
if(relativePositionOnGridX >=0){
|
||||||
if(relativePositionOnGridZ >= 0){
|
if(relativePositionOnGridZ >= 0){
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package electrosphere.client.sim;
|
package electrosphere.client.sim;
|
||||||
|
|
||||||
|
import electrosphere.client.fluid.manager.ClientFluidManager;
|
||||||
import electrosphere.client.instancing.InstanceUpdater;
|
import electrosphere.client.instancing.InstanceUpdater;
|
||||||
import electrosphere.client.terrain.manager.ClientTerrainManager;
|
import electrosphere.client.terrain.manager.ClientTerrainManager;
|
||||||
import electrosphere.engine.Globals;
|
import electrosphere.engine.Globals;
|
||||||
@ -27,6 +28,7 @@ public class ClientFunctions {
|
|||||||
|
|
||||||
public static void runClientFunctions(){
|
public static void runClientFunctions(){
|
||||||
ClientTerrainManager.generateTerrainChunkGeometry();
|
ClientTerrainManager.generateTerrainChunkGeometry();
|
||||||
|
ClientFluidManager.generateFluidChunkGeometry();
|
||||||
updateSkyboxPos();
|
updateSkyboxPos();
|
||||||
Globals.clientSceneWrapper.destroyEntitiesOutsideSimRange();
|
Globals.clientSceneWrapper.destroyEntitiesOutsideSimRange();
|
||||||
InstanceUpdater.updateInstancedActorPriority();
|
InstanceUpdater.updateInstancedActorPriority();
|
||||||
@ -48,11 +50,15 @@ public class ClientFunctions {
|
|||||||
public static void loadTerrain(){
|
public static void loadTerrain(){
|
||||||
if(Globals.clientTerrainManager != null){
|
if(Globals.clientTerrainManager != null){
|
||||||
Globals.clientTerrainManager.handleMessages();
|
Globals.clientTerrainManager.handleMessages();
|
||||||
updateCellManager();
|
updateTerrainCellManager();
|
||||||
|
}
|
||||||
|
if(Globals.clientFluidManager != null){
|
||||||
|
Globals.clientFluidManager.handleMessages();
|
||||||
|
updateFluidCellManager();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateCellManager(){
|
static void updateTerrainCellManager(){
|
||||||
///
|
///
|
||||||
/// C L I E N T C E L L M A N A G E R
|
/// C L I E N T C E L L M A N A G E R
|
||||||
///
|
///
|
||||||
@ -65,4 +71,15 @@ public class ClientFunctions {
|
|||||||
Globals.drawCellManager.update();
|
Globals.drawCellManager.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void updateFluidCellManager(){
|
||||||
|
//fluid work
|
||||||
|
if(Globals.fluidCellManager != null && Globals.clientWorldData != null){
|
||||||
|
if(Globals.playerEntity != null){
|
||||||
|
newPlayerCharacterPosition = EntityUtils.getPosition(Globals.playerEntity);
|
||||||
|
}
|
||||||
|
Globals.fluidCellManager.calculateDeltas(newPlayerCharacterPosition);
|
||||||
|
Globals.fluidCellManager.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import electrosphere.audio.AudioEngine;
|
|||||||
import electrosphere.audio.VirtualAudioSourceManager;
|
import electrosphere.audio.VirtualAudioSourceManager;
|
||||||
import electrosphere.auth.AuthenticationManager;
|
import electrosphere.auth.AuthenticationManager;
|
||||||
import electrosphere.client.culling.ClientEntityCullingManager;
|
import electrosphere.client.culling.ClientEntityCullingManager;
|
||||||
|
import electrosphere.client.fluid.cells.FluidCellManager;
|
||||||
import electrosphere.client.fluid.manager.ClientFluidManager;
|
import electrosphere.client.fluid.manager.ClientFluidManager;
|
||||||
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
||||||
import electrosphere.client.player.ClientPlayerData;
|
import electrosphere.client.player.ClientPlayerData;
|
||||||
@ -52,6 +53,7 @@ import electrosphere.renderer.actor.instance.InstanceManager;
|
|||||||
import electrosphere.renderer.light.PointLight;
|
import electrosphere.renderer.light.PointLight;
|
||||||
import electrosphere.renderer.light.SpotLight;
|
import electrosphere.renderer.light.SpotLight;
|
||||||
import electrosphere.renderer.loading.ModelPretransforms;
|
import electrosphere.renderer.loading.ModelPretransforms;
|
||||||
|
import electrosphere.renderer.meshgen.FluidChunkModelGeneration;
|
||||||
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
|
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
|
||||||
import electrosphere.renderer.model.Material;
|
import electrosphere.renderer.model.Material;
|
||||||
import electrosphere.renderer.shader.ShaderOptionMap;
|
import electrosphere.renderer.shader.ShaderOptionMap;
|
||||||
@ -66,6 +68,7 @@ import electrosphere.server.content.ServerContentManager;
|
|||||||
import electrosphere.server.datacell.EntityDataCellMapper;
|
import electrosphere.server.datacell.EntityDataCellMapper;
|
||||||
import electrosphere.server.datacell.RealmManager;
|
import electrosphere.server.datacell.RealmManager;
|
||||||
import electrosphere.server.db.DatabaseController;
|
import electrosphere.server.db.DatabaseController;
|
||||||
|
import electrosphere.server.fluid.manager.ServerFluidManager;
|
||||||
import electrosphere.server.pathfinding.NavMeshManager;
|
import electrosphere.server.pathfinding.NavMeshManager;
|
||||||
import electrosphere.server.simulation.MacroSimulation;
|
import electrosphere.server.simulation.MacroSimulation;
|
||||||
import electrosphere.server.simulation.MicroSimulation;
|
import electrosphere.server.simulation.MicroSimulation;
|
||||||
@ -254,6 +257,12 @@ public class Globals {
|
|||||||
//terrain manager
|
//terrain manager
|
||||||
// public static boolean LOAD_TERRAIN = true;
|
// public static boolean LOAD_TERRAIN = true;
|
||||||
public static ServerTerrainManager serverTerrainManager;
|
public static ServerTerrainManager serverTerrainManager;
|
||||||
|
|
||||||
|
|
||||||
|
//fluid manager
|
||||||
|
public static ServerFluidManager serverFluidManager;
|
||||||
|
|
||||||
|
//spawn point
|
||||||
public static Vector3d spawnPoint = new Vector3d(0,0,0);
|
public static Vector3d spawnPoint = new Vector3d(0,0,0);
|
||||||
|
|
||||||
//content manager
|
//content manager
|
||||||
@ -304,8 +313,11 @@ public class Globals {
|
|||||||
public static ClientPlayerData clientPlayerData = new ClientPlayerData();
|
public static ClientPlayerData clientPlayerData = new ClientPlayerData();
|
||||||
|
|
||||||
//chunk stuff
|
//chunk stuff
|
||||||
//constant for how far in game units you have to move to load chunks
|
//draw cell manager
|
||||||
public static DrawCellManager drawCellManager;
|
public static DrawCellManager drawCellManager;
|
||||||
|
|
||||||
|
//fluid cell manager
|
||||||
|
public static FluidCellManager fluidCellManager;
|
||||||
|
|
||||||
//navmesh manager
|
//navmesh manager
|
||||||
public static NavMeshManager navMeshManager;
|
public static NavMeshManager navMeshManager;
|
||||||
@ -413,6 +425,8 @@ public class Globals {
|
|||||||
navMeshManager = new NavMeshManager();
|
navMeshManager = new NavMeshManager();
|
||||||
//terrain
|
//terrain
|
||||||
Globals.clientTerrainManager = new ClientTerrainManager();
|
Globals.clientTerrainManager = new ClientTerrainManager();
|
||||||
|
//fluid
|
||||||
|
Globals.clientFluidManager = new ClientFluidManager();
|
||||||
//game config
|
//game config
|
||||||
gameConfigDefault = electrosphere.game.data.Config.loadDefaultConfig();
|
gameConfigDefault = electrosphere.game.data.Config.loadDefaultConfig();
|
||||||
gameConfigCurrent = gameConfigDefault;
|
gameConfigCurrent = gameConfigDefault;
|
||||||
@ -471,8 +485,7 @@ public class Globals {
|
|||||||
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain2.vs", "/Shaders/terrain2/terrain2.fs");
|
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain2.vs", "/Shaders/terrain2/terrain2.fs");
|
||||||
TerrainChunkModelGeneration.terrainChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain2.vs", "/Shaders/terrain2/terrain2.fs");
|
TerrainChunkModelGeneration.terrainChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain2.vs", "/Shaders/terrain2/terrain2.fs");
|
||||||
//init fluid shader program
|
//init fluid shader program
|
||||||
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid1/fluid1.vs", "/Shaders/fluid1/fluid1.fs");
|
FluidChunkModelGeneration.fluidChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid2/fluid2.vs", "/Shaders/fluid2/fluid2.fs");
|
||||||
TerrainChunkModelGeneration.terrainChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid1/fluid1.vs", "/Shaders/fluid1/fluid1.fs");
|
|
||||||
//init models
|
//init models
|
||||||
assetManager.addModelPathToQueue("Models/unitsphere.fbx");
|
assetManager.addModelPathToQueue("Models/unitsphere.fbx");
|
||||||
assetManager.addModelPathToQueue("Models/unitsphere_1.fbx");
|
assetManager.addModelPathToQueue("Models/unitsphere_1.fbx");
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import electrosphere.entity.ServerEntityUtils;
|
|||||||
import electrosphere.game.server.world.ServerWorldData;
|
import electrosphere.game.server.world.ServerWorldData;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.server.content.ServerContentManager;
|
import electrosphere.server.content.ServerContentManager;
|
||||||
|
import electrosphere.server.fluid.manager.ServerFluidManager;
|
||||||
import electrosphere.server.saves.SaveUtils;
|
import electrosphere.server.saves.SaveUtils;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
import electrosphere.util.FileUtils;
|
import electrosphere.util.FileUtils;
|
||||||
@ -56,6 +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();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void initServerArenaWorldData(){
|
private static void initServerArenaWorldData(){
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import electrosphere.audio.AudioUtils;
|
|||||||
import electrosphere.audio.VirtualAudioSource;
|
import electrosphere.audio.VirtualAudioSource;
|
||||||
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
|
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
|
||||||
import electrosphere.client.culling.ClientEntityCullingManager;
|
import electrosphere.client.culling.ClientEntityCullingManager;
|
||||||
|
import electrosphere.client.fluid.cells.FluidCellManager;
|
||||||
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
||||||
import electrosphere.client.sim.ClientSimulation;
|
import electrosphere.client.sim.ClientSimulation;
|
||||||
import electrosphere.client.targeting.crosshair.Crosshair;
|
import electrosphere.client.targeting.crosshair.Crosshair;
|
||||||
@ -93,6 +94,8 @@ public class ClientLoading {
|
|||||||
initFoliageManager();
|
initFoliageManager();
|
||||||
//initialize the cell manager (client)
|
//initialize the cell manager (client)
|
||||||
initDrawCellManager();
|
initDrawCellManager();
|
||||||
|
//init the fluid cell manager
|
||||||
|
initFluidCellManager();
|
||||||
//initialize the basic graphical entities of the world (skybox, camera)
|
//initialize the basic graphical entities of the world (skybox, camera)
|
||||||
initWorldBaseGraphicalEntities();
|
initWorldBaseGraphicalEntities();
|
||||||
//init arena specific stuff (ie different skybox colors)
|
//init arena specific stuff (ie different skybox colors)
|
||||||
@ -290,6 +293,41 @@ public class ClientLoading {
|
|||||||
// System.out.println("Draw Cell Manager ready");
|
// System.out.println("Draw Cell Manager ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void initFluidCellManager(){
|
||||||
|
while(Globals.clientWorldData == null){
|
||||||
|
try {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(10);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//initialize draw cell manager
|
||||||
|
Globals.fluidCellManager = new FluidCellManager(Globals.clientTerrainManager, 0, 0, 0);
|
||||||
|
//set our draw cell manager to actually generate drawable chunks
|
||||||
|
Globals.fluidCellManager.setGenerateDrawables(true);
|
||||||
|
//Alerts the client simulation that it should start loading terrain
|
||||||
|
Globals.clientSimulation.setLoadingTerrain(true);
|
||||||
|
//wait for all the terrain data to arrive
|
||||||
|
while(Globals.fluidCellManager.containsUnrequestedCell()){
|
||||||
|
// Globals.drawCellManager.updateInvalidCell();
|
||||||
|
try {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(10);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
// System.out.println("invalid cell");
|
||||||
|
}
|
||||||
|
|
||||||
|
while(Globals.fluidCellManager.containsUndrawableCell()){
|
||||||
|
// Globals.drawCellManager.makeCellDrawable();
|
||||||
|
try {
|
||||||
|
TimeUnit.MILLISECONDS.sleep(10);
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
// System.out.println("undrawable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts up the entity culling manager
|
* Starts up the entity culling manager
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -17,9 +17,9 @@ public class FluidChunk {
|
|||||||
* @param values The values (block types)
|
* @param values The values (block types)
|
||||||
* @return The fluid chunk entity
|
* @return The fluid chunk entity
|
||||||
*/
|
*/
|
||||||
public static Entity clientCreateFluidChunkEntity(float[][][] weights, int[][][] values){
|
public static Entity clientCreateFluidChunkEntity(float[][][] weights){
|
||||||
|
|
||||||
FluidChunkModelData data = FluidChunkModelGeneration.generateFluidChunkData(weights, values);
|
FluidChunkModelData data = FluidChunkModelGeneration.generateFluidChunkData(weights);
|
||||||
String modelPath = ClientFluidManager.queueFluidGridGeneration(data);
|
String modelPath = ClientFluidManager.queueFluidGridGeneration(data);
|
||||||
|
|
||||||
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
|
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public class LoggerInterface {
|
|||||||
|
|
||||||
public static void initLoggers(){
|
public static void initLoggers(){
|
||||||
loggerStartup = new Logger(LogLevel.WARNING);
|
loggerStartup = new Logger(LogLevel.WARNING);
|
||||||
loggerNetworking = new Logger(LogLevel.WARNING);
|
loggerNetworking = new Logger(LogLevel.DEBUG);
|
||||||
loggerFileIO = new Logger(LogLevel.WARNING);
|
loggerFileIO = new Logger(LogLevel.WARNING);
|
||||||
loggerGameLogic = new Logger(LogLevel.WARNING);
|
loggerGameLogic = new Logger(LogLevel.WARNING);
|
||||||
loggerRenderer = new Logger(LogLevel.WARNING);
|
loggerRenderer = new Logger(LogLevel.WARNING);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package electrosphere.net.client.protocol;
|
|||||||
|
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
import electrosphere.client.fluid.cache.FluidChunkData;
|
||||||
import electrosphere.client.scene.ClientWorldData;
|
import electrosphere.client.scene.ClientWorldData;
|
||||||
import electrosphere.client.terrain.cache.ChunkData;
|
import electrosphere.client.terrain.cache.ChunkData;
|
||||||
import electrosphere.collision.CollisionWorldData;
|
import electrosphere.collision.CollisionWorldData;
|
||||||
@ -49,6 +50,9 @@ public class TerrainProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case SENDFLUIDDATA: {
|
||||||
|
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;
|
||||||
|
|||||||
@ -236,6 +236,16 @@ SYNCHRONIZATION_MESSAGE,
|
|||||||
rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer);
|
rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA:
|
||||||
|
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
|
||||||
|
rVal = TerrainMessage.parseRequestFluidDataMessage(byteBuffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA:
|
||||||
|
if(TerrainMessage.canParseMessage(byteBuffer,secondByte)){
|
||||||
|
rVal = TerrainMessage.parsesendFluidDataMessage(byteBuffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TypeBytes.MESSAGE_TYPE_SERVER:
|
case TypeBytes.MESSAGE_TYPE_SERVER:
|
||||||
|
|||||||
@ -17,6 +17,8 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
SPAWNPOSITION,
|
SPAWNPOSITION,
|
||||||
REQUESTCHUNKDATA,
|
REQUESTCHUNKDATA,
|
||||||
SENDCHUNKDATA,
|
SENDCHUNKDATA,
|
||||||
|
REQUESTFLUIDDATA,
|
||||||
|
SENDFLUIDDATA,
|
||||||
}
|
}
|
||||||
|
|
||||||
TerrainMessageType messageType;
|
TerrainMessageType messageType;
|
||||||
@ -266,6 +268,14 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
}
|
}
|
||||||
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA:
|
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA:
|
||||||
return TerrainMessage.canParsesendChunkDataMessage(byteBuffer);
|
return TerrainMessage.canParsesendChunkDataMessage(byteBuffer);
|
||||||
|
case TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA:
|
||||||
|
if(byteBuffer.getRemaining() >= TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE){
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA:
|
||||||
|
return TerrainMessage.canParsesendFluidDataMessage(byteBuffer);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -488,6 +498,72 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TerrainMessage parseRequestFluidDataMessage(CircularByteBuffer byteBuffer){
|
||||||
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTFLUIDDATA);
|
||||||
|
stripPacketHeader(byteBuffer);
|
||||||
|
rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
|
||||||
|
rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
|
||||||
|
rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TerrainMessage constructRequestFluidDataMessage(int worldX,int worldY,int worldZ){
|
||||||
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.REQUESTFLUIDDATA);
|
||||||
|
rVal.setworldX(worldX);
|
||||||
|
rVal.setworldY(worldY);
|
||||||
|
rVal.setworldZ(worldZ);
|
||||||
|
rVal.serialize();
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean canParsesendFluidDataMessage(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 parsesendFluidDataMessage(CircularByteBuffer byteBuffer){
|
||||||
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDFLUIDDATA);
|
||||||
|
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 constructsendFluidDataMessage(int worldX,int worldY,int worldZ,byte[] chunkData){
|
||||||
|
TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SENDFLUIDDATA);
|
||||||
|
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];
|
||||||
@ -718,6 +794,51 @@ public class TerrainMessage extends NetworkMessage {
|
|||||||
rawBytes[18+i] = chunkData[i];
|
rawBytes[18+i] = chunkData[i];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case REQUESTFLUIDDATA:
|
||||||
|
rawBytes = new byte[2+4+4+4];
|
||||||
|
//message header
|
||||||
|
rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN;
|
||||||
|
//entity messaage header
|
||||||
|
rawBytes[1] = TypeBytes.TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA;
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SENDFLUIDDATA:
|
||||||
|
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_SENDFLUIDDATA;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,6 +88,8 @@ Message categories
|
|||||||
public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION = 6;
|
public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION = 6;
|
||||||
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA = 7;
|
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA = 7;
|
||||||
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_SENDFLUIDDATA = 10;
|
||||||
/*
|
/*
|
||||||
Terrain packet sizes
|
Terrain packet sizes
|
||||||
*/
|
*/
|
||||||
@ -99,6 +101,7 @@ Message categories
|
|||||||
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE_SIZE = 38;
|
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTUSETERRAINPALETTE_SIZE = 38;
|
||||||
public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION_SIZE = 26;
|
public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION_SIZE = 26;
|
||||||
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA_SIZE = 14;
|
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA_SIZE = 14;
|
||||||
|
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE = 14;
|
||||||
/*
|
/*
|
||||||
Server subcategories
|
Server subcategories
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
package electrosphere.net.parser.net.raw;
|
package electrosphere.net.parser.net.raw;
|
||||||
|
|
||||||
import electrosphere.logger.LoggerInterface;
|
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;
|
||||||
@ -52,7 +51,7 @@ public class NetworkParser {
|
|||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
LoggerInterface.loggerNetworking.ERROR("", ex);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import electrosphere.net.server.Server;
|
|||||||
import electrosphere.net.server.ServerConnectionHandler;
|
import electrosphere.net.server.ServerConnectionHandler;
|
||||||
import electrosphere.net.server.player.Player;
|
import electrosphere.net.server.player.Player;
|
||||||
import electrosphere.server.datacell.Realm;
|
import electrosphere.server.datacell.Realm;
|
||||||
|
import electrosphere.server.fluid.manager.ServerFluidChunk;
|
||||||
import electrosphere.server.terrain.editing.TerrainEditing;
|
import electrosphere.server.terrain.editing.TerrainEditing;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
import electrosphere.server.terrain.models.TerrainModification;
|
import electrosphere.server.terrain.models.TerrainModification;
|
||||||
@ -38,11 +39,17 @@ public class TerrainProtocol {
|
|||||||
case REQUESTUSETERRAINPALETTE: {
|
case REQUESTUSETERRAINPALETTE: {
|
||||||
attemptUseTerrainEditPalette(connectionHandler, message);
|
attemptUseTerrainEditPalette(connectionHandler, message);
|
||||||
} break;
|
} break;
|
||||||
|
case REQUESTFLUIDDATA: {
|
||||||
|
sendWorldFluidSubChunk(connectionHandler,
|
||||||
|
message.getworldX(), message.getworldY(), message.getworldZ()
|
||||||
|
);
|
||||||
|
} break;
|
||||||
//all ignored message types
|
//all ignored message types
|
||||||
case RESPONSEMETADATA:
|
case RESPONSEMETADATA:
|
||||||
case SPAWNPOSITION:
|
case SPAWNPOSITION:
|
||||||
case UPDATEVOXEL:
|
case UPDATEVOXEL:
|
||||||
case SENDCHUNKDATA:
|
case SENDCHUNKDATA:
|
||||||
|
case SENDFLUIDDATA:
|
||||||
//silently ignore
|
//silently ignore
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -194,6 +201,64 @@ public class TerrainProtocol {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void sendWorldFluidSubChunk(ServerConnectionHandler connectionHandler, int worldX, int worldY, int worldZ){
|
||||||
|
|
||||||
|
// System.out.println("Received request for chunk " + message.getworldX() + " " + message.getworldY());
|
||||||
|
|
||||||
|
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());
|
||||||
|
|
||||||
|
//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.
|
||||||
|
int xWidth = chunk.getWeights().length;
|
||||||
|
int yWidth = chunk.getWeights()[0].length;
|
||||||
|
int zWidth = chunk.getWeights()[0][0].length;
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(xWidth*yWidth*zWidth*(4+4+4+4));
|
||||||
|
FloatBuffer floatView = buffer.asFloatBuffer();
|
||||||
|
|
||||||
|
for(int x = 0; x < xWidth; x++){
|
||||||
|
for(int y = 0; y < yWidth; y++){
|
||||||
|
for(int z = 0; z < zWidth; z++){
|
||||||
|
floatView.put(chunk.getWeights()[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int x = 0; x < xWidth; x++){
|
||||||
|
for(int y = 0; y < yWidth; y++){
|
||||||
|
for(int z = 0; z < zWidth; z++){
|
||||||
|
floatView.put(chunk.getVelocityX()[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int x = 0; x < xWidth; x++){
|
||||||
|
for(int y = 0; y < yWidth; y++){
|
||||||
|
for(int z = 0; z < zWidth; z++){
|
||||||
|
floatView.put(chunk.getVelocityY()[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int x = 0; x < xWidth; x++){
|
||||||
|
for(int y = 0; y < yWidth; y++){
|
||||||
|
for(int z = 0; z < zWidth; z++){
|
||||||
|
floatView.put(chunk.getVelocityZ()[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
connectionHandler.addMessagetoOutgoingQueue(TerrainMessage.constructsendFluidDataMessage(worldX, worldY, worldZ, buffer.array()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void sendWorldMetadata(ServerConnectionHandler connectionHandler){
|
static void sendWorldMetadata(ServerConnectionHandler connectionHandler){
|
||||||
//world metadata
|
//world metadata
|
||||||
connectionHandler.addMessagetoOutgoingQueue(
|
connectionHandler.addMessagetoOutgoingQueue(
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import electrosphere.renderer.model.Material;
|
|||||||
import electrosphere.renderer.model.Mesh;
|
import electrosphere.renderer.model.Mesh;
|
||||||
import electrosphere.renderer.model.Model;
|
import electrosphere.renderer.model.Model;
|
||||||
import electrosphere.renderer.shader.ShaderProgram;
|
import electrosphere.renderer.shader.ShaderProgram;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
|
||||||
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||||
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
|
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
|
||||||
@ -559,7 +560,7 @@ public class FluidChunkModelGeneration {
|
|||||||
return new Vector3f(x,y,z);
|
return new Vector3f(x,y,z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FluidChunkModelData generateFluidChunkData(float[][][] weightGrid, int[][][] typeGrid){
|
public static FluidChunkModelData generateFluidChunkData(float[][][] weightGrid){
|
||||||
|
|
||||||
// 5 6
|
// 5 6
|
||||||
// +-------------+ +-----5-------+ ^ Y
|
// +-------------+ +-----5-------+ ^ Y
|
||||||
@ -593,6 +594,9 @@ public class FluidChunkModelGeneration {
|
|||||||
for(int x = 0; x < weightGrid.length - 1; x++){
|
for(int x = 0; x < weightGrid.length - 1; x++){
|
||||||
for(int y = 0; y < weightGrid[0].length - 1; y++){
|
for(int y = 0; y < weightGrid[0].length - 1; y++){
|
||||||
for(int z = 0; z < weightGrid[0][0].length - 1; z++){
|
for(int z = 0; z < weightGrid[0][0].length - 1; z++){
|
||||||
|
if(x == 3 && y == 3 && z == 3){
|
||||||
|
System.out.println("erihjy at 3,3,3 " + weightGrid[x][y][z]);
|
||||||
|
}
|
||||||
//push the current cell's values into the gridcell
|
//push the current cell's values into the gridcell
|
||||||
currentCell.setValues(
|
currentCell.setValues(
|
||||||
new Vector3f(x+0,y+0,z+0), new Vector3f(x+0,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+0),
|
new Vector3f(x+0,y+0,z+0), new Vector3f(x+0,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+0),
|
||||||
@ -665,6 +669,10 @@ public class FluidChunkModelGeneration {
|
|||||||
UVs.add(temp[1]);
|
UVs.add(temp[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
System.out.println("weight at 3 3 3 " + weightGrid[3][3][3]);
|
||||||
|
|
||||||
|
System.out.println("Fluid verts: " + vertsFlat.size());
|
||||||
|
|
||||||
//List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs
|
//List<Float> vertices, List<Float> normals, List<Integer> faceElements, List<Float> uvs
|
||||||
FluidChunkModelData rVal = new FluidChunkModelData(vertsFlat, normalsFlat, elementsFlat, UVs);
|
FluidChunkModelData rVal = new FluidChunkModelData(vertsFlat, normalsFlat, elementsFlat, UVs);
|
||||||
return rVal;
|
return rVal;
|
||||||
@ -768,7 +776,13 @@ public class FluidChunkModelGeneration {
|
|||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float halfChunk = ServerTerrainChunk.CHUNK_DIMENSION / 2.0f;
|
||||||
|
mesh.updateBoundingSphere(
|
||||||
|
halfChunk,
|
||||||
|
halfChunk,
|
||||||
|
halfChunk,
|
||||||
|
(float)Math.sqrt(halfChunk * halfChunk + halfChunk * halfChunk + halfChunk * halfChunk)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
@ -796,6 +810,7 @@ public class FluidChunkModelGeneration {
|
|||||||
m.setParent(rVal);
|
m.setParent(rVal);
|
||||||
|
|
||||||
rVal.getMeshes().add(m);
|
rVal.getMeshes().add(m);
|
||||||
|
rVal.setBoundingSphere(m.getBoundingSphere());
|
||||||
|
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -599,6 +599,9 @@ public class TerrainChunkModelGeneration {
|
|||||||
for(int x = 0; x < terrainGrid.length - 1; x++){
|
for(int x = 0; x < terrainGrid.length - 1; x++){
|
||||||
for(int y = 0; y < terrainGrid[0].length - 1; y++){
|
for(int y = 0; y < terrainGrid[0].length - 1; y++){
|
||||||
for(int z = 0; z < terrainGrid[0][0].length - 1; z++){
|
for(int z = 0; z < terrainGrid[0][0].length - 1; z++){
|
||||||
|
if(x == 0 && y == 0 && z == 0){
|
||||||
|
System.out.println("asdf");
|
||||||
|
}
|
||||||
//push the current cell's values into the gridcell
|
//push the current cell's values into the gridcell
|
||||||
currentCell.setValues(
|
currentCell.setValues(
|
||||||
new Vector3f(x+0,y+0,z+0), new Vector3f(x+0,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+0),
|
new Vector3f(x+0,y+0,z+0), new Vector3f(x+0,y+0,z+1), new Vector3f(x+1,y+0,z+1), new Vector3f(x+1,y+0,z+0),
|
||||||
|
|||||||
@ -21,6 +21,8 @@ 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;
|
||||||
import electrosphere.server.datacell.physics.PhysicsDataCell;
|
import electrosphere.server.datacell.physics.PhysicsDataCell;
|
||||||
|
import electrosphere.server.fluid.manager.ServerFluidChunk;
|
||||||
|
import electrosphere.server.fluid.manager.ServerFluidManager;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
|
||||||
@ -43,6 +45,8 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
Realm parent;
|
Realm parent;
|
||||||
//Manager for terrain for this particular cell manager
|
//Manager for terrain for this particular cell manager
|
||||||
ServerTerrainManager serverTerrainManager;
|
ServerTerrainManager serverTerrainManager;
|
||||||
|
//manager for fluids for this particular cell manager
|
||||||
|
ServerFluidManager serverFluidManager;
|
||||||
//lock for terrain editing
|
//lock for terrain editing
|
||||||
Semaphore terrainEditLock = new Semaphore(1);
|
Semaphore terrainEditLock = new Semaphore(1);
|
||||||
//manager for getting entities to fill in a cell
|
//manager for getting entities to fill in a cell
|
||||||
@ -52,9 +56,15 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
* Constructor
|
* Constructor
|
||||||
* @param parent The gridded data cell manager's parent realm
|
* @param parent The gridded data cell manager's parent realm
|
||||||
*/
|
*/
|
||||||
public GriddedDataCellManager(Realm parent, ServerTerrainManager serverTerrainManager, ServerContentManager serverContentManager) {
|
public GriddedDataCellManager(
|
||||||
|
Realm parent,
|
||||||
|
ServerTerrainManager serverTerrainManager,
|
||||||
|
ServerFluidManager serverFluidManager,
|
||||||
|
ServerContentManager serverContentManager
|
||||||
|
) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.serverTerrainManager = serverTerrainManager;
|
this.serverTerrainManager = serverTerrainManager;
|
||||||
|
this.serverFluidManager = serverFluidManager;
|
||||||
this.serverContentManager = serverContentManager;
|
this.serverContentManager = serverContentManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,6 +354,8 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
for(ServerDataCell cell : loadedCells){
|
for(ServerDataCell cell : loadedCells){
|
||||||
Globals.microSimulation.simulate(cell, parent.getHitboxManager());
|
Globals.microSimulation.simulate(cell, parent.getHitboxManager());
|
||||||
}
|
}
|
||||||
|
//simulate fluid
|
||||||
|
this.serverFluidManager.simulate();
|
||||||
loadedCellsLock.release();
|
loadedCellsLock.release();
|
||||||
updatePlayerPositions();
|
updatePlayerPositions();
|
||||||
}
|
}
|
||||||
@ -357,6 +369,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
return serverTerrainManager;
|
return serverTerrainManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the server fluid manager for this realm if it exists
|
||||||
|
* @return The server fluid manager if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public ServerFluidManager getServerFluidManager(){
|
||||||
|
return serverFluidManager;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs code to generate physics entities and register cell in a dedicated thread.
|
* Runs code to generate physics entities and register cell in a dedicated thread.
|
||||||
* Because cell hasn't been registered yet, no simulation is performed until the physics is created.
|
* Because cell hasn't been registered yet, no simulation is performed until the physics is created.
|
||||||
@ -461,4 +481,9 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
|||||||
return cellPositionMap.get(cell);
|
return cellPositionMap.get(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerFluidChunk getFluidChunkAtPosition(Vector3i worldPosition) {
|
||||||
|
return serverFluidManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,7 +53,7 @@ public class RealmManager {
|
|||||||
//create realm
|
//create realm
|
||||||
Realm realm = new Realm(collisionEngine, new HitboxManager());
|
Realm realm = new Realm(collisionEngine, new HitboxManager());
|
||||||
//create function classes
|
//create function classes
|
||||||
GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm,Globals.serverTerrainManager,Globals.serverContentManager);
|
GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm,Globals.serverTerrainManager,Globals.serverFluidManager,Globals.serverContentManager);
|
||||||
EntityDataCellMapper entityDataCellMapper = new EntityDataCellMapper();
|
EntityDataCellMapper entityDataCellMapper = new EntityDataCellMapper();
|
||||||
//init gridded manager
|
//init gridded manager
|
||||||
griddedDataCellManager.init(serverWorldData);
|
griddedDataCellManager.init(serverWorldData);
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package electrosphere.server.datacell.interfaces;
|
|||||||
|
|
||||||
import org.joml.Vector3i;
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
import electrosphere.server.fluid.manager.ServerFluidChunk;
|
||||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,5 +41,13 @@ public interface VoxelCellManager {
|
|||||||
* @param type The type to set the voxel to
|
* @param type The type to set the voxel to
|
||||||
*/
|
*/
|
||||||
public void editChunk(Vector3i worldPosition, Vector3i voxelPosition, float weight, int type);
|
public void editChunk(Vector3i worldPosition, Vector3i voxelPosition, float weight, int type);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the fluid chunk at a given world position
|
||||||
|
* @param worldPosition The world position
|
||||||
|
* @return the fluid chunk
|
||||||
|
*/
|
||||||
|
public ServerFluidChunk getFluidChunkAtPosition(Vector3i worldPosition);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,217 @@
|
|||||||
|
package electrosphere.server.fluid.diskmap;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.nio.IntBuffer;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.DeflaterInputStream;
|
||||||
|
import java.util.zip.DeflaterOutputStream;
|
||||||
|
import java.util.zip.InflaterOutputStream;
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
import electrosphere.logger.LoggerInterface;
|
||||||
|
import electrosphere.net.server.Server;
|
||||||
|
import electrosphere.server.fluid.manager.ServerFluidChunk;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
import electrosphere.util.FileUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface for accessing the disk map of chunk information
|
||||||
|
*/
|
||||||
|
public class FluidDiskMap {
|
||||||
|
|
||||||
|
//The map of world position+chunk type to the file that actually houses that information
|
||||||
|
Map<String,String> worldPosFileMap = new HashMap<String,String>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public FluidDiskMap(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a key for a given chunk file based on a world coordinate
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return The key
|
||||||
|
*/
|
||||||
|
private static String getFluidChunkKey(int worldX, int worldY, int worldZ){
|
||||||
|
return worldX + "_" + worldY + "_" + worldZ + "f";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a diskmap based on a given save name
|
||||||
|
* @param saveName The save name
|
||||||
|
*/
|
||||||
|
public void init(String saveName){
|
||||||
|
LoggerInterface.loggerEngine.DEBUG("INIT CHUNK MAP " + saveName);
|
||||||
|
if(FileUtils.getSaveFile(saveName, "chunk.map").exists()){
|
||||||
|
worldPosFileMap = FileUtils.loadObjectFromSavePath(saveName, "fluid.map", Map.class);
|
||||||
|
LoggerInterface.loggerEngine.DEBUG("POS FILE MAP: " + worldPosFileMap.keySet());
|
||||||
|
} else {
|
||||||
|
worldPosFileMap = new HashMap<String,String>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the disk map to disk
|
||||||
|
*/
|
||||||
|
public void save(){
|
||||||
|
FileUtils.serializeObjectToSavePath(Globals.currentSaveName, "fluid.map", worldPosFileMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the map contains a given chunk position
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return True if the map contains the chunk, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean containsFluidAtPosition(int worldX, int worldY, int worldZ){
|
||||||
|
return worldPosFileMap.containsKey(getFluidChunkKey(worldX, worldY, worldZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the server fluid chunk from disk if it exists, otherwise returns null
|
||||||
|
* @param worldX The x coordinate
|
||||||
|
* @param worldY The y coordinate
|
||||||
|
* @param worldZ The z coordinate
|
||||||
|
* @return The server fluid chunk if it exists, null otherwise
|
||||||
|
*/
|
||||||
|
public ServerFluidChunk getFluidChunk(int worldX, int worldY, int worldZ){
|
||||||
|
LoggerInterface.loggerEngine.INFO("Load chunk " + worldX + " " + worldY + " " + worldZ);
|
||||||
|
ServerFluidChunk rVal = null;
|
||||||
|
if(containsFluidAtPosition(worldX, worldY, worldZ)){
|
||||||
|
//read file
|
||||||
|
String fileName = worldPosFileMap.get(getFluidChunkKey(worldX, worldY, worldZ));
|
||||||
|
byte[] rawDataCompressed = FileUtils.loadBinaryFromSavePath(Globals.currentSaveName, fileName);
|
||||||
|
//decompress
|
||||||
|
byte[] rawData = null;
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
InflaterOutputStream inflaterInputStream = new InflaterOutputStream(out);
|
||||||
|
try {
|
||||||
|
inflaterInputStream.write(rawDataCompressed);
|
||||||
|
inflaterInputStream.flush();
|
||||||
|
inflaterInputStream.close();
|
||||||
|
rawData = out.toByteArray();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
//parse
|
||||||
|
if(rawData != null){
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(rawData);
|
||||||
|
FloatBuffer floatView = buffer.asFloatBuffer();
|
||||||
|
int DIM = ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
float[][][] weights = new float[DIM][DIM][DIM];
|
||||||
|
float[][][] velocityX = new float[DIM][DIM][DIM];
|
||||||
|
float[][][] velocityY = new float[DIM][DIM][DIM];
|
||||||
|
float[][][] velocityZ = new float[DIM][DIM][DIM];
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
weights[x][y][z] = floatView.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
velocityX[x][y][z] = floatView.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
velocityY[x][y][z] = floatView.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
velocityZ[x][y][z] = floatView.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rVal = new ServerFluidChunk(worldX, worldY, worldZ, weights, velocityX, velocityY, velocityZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a fluid chunk to disk
|
||||||
|
* @param fluidChunk The fluid chunk
|
||||||
|
*/
|
||||||
|
public void saveToDisk(ServerFluidChunk fluidChunk){
|
||||||
|
LoggerInterface.loggerEngine.DEBUG("Save to disk: " + fluidChunk.getWorldX() + " " + fluidChunk.getWorldY() + " " + fluidChunk.getWorldZ());
|
||||||
|
//get the file name for this chunk
|
||||||
|
String fileName = null;
|
||||||
|
String chunkKey = getFluidChunkKey(fluidChunk.getWorldX(),fluidChunk.getWorldY(),fluidChunk.getWorldZ());
|
||||||
|
if(worldPosFileMap.containsKey(chunkKey)){
|
||||||
|
fileName = worldPosFileMap.get(chunkKey);
|
||||||
|
} else {
|
||||||
|
fileName = chunkKey + ".dat";
|
||||||
|
}
|
||||||
|
//generate binary for the file
|
||||||
|
float[][][] weights = fluidChunk.getWeights();
|
||||||
|
float[][][] velocityX = fluidChunk.getVelocityX();
|
||||||
|
float[][][] velocityY = fluidChunk.getVelocityY();
|
||||||
|
float[][][] velocityZ = fluidChunk.getVelocityZ();
|
||||||
|
int DIM = ServerTerrainChunk.CHUNK_DIMENSION;
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(DIM * DIM * DIM * 4 + DIM * DIM * DIM * 4 + DIM * DIM * DIM * 4 + DIM * DIM * DIM * 4);
|
||||||
|
FloatBuffer floatView = buffer.asFloatBuffer();
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
floatView.put(weights[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
floatView.put(velocityX[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
floatView.put(velocityY[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(int x = 0; x < DIM; x++){
|
||||||
|
for(int y = 0; y < DIM; y++){
|
||||||
|
for(int z = 0; z < DIM; z++){
|
||||||
|
floatView.put(velocityZ[x][y][z]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//compress
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
DeflaterOutputStream deflaterInputStream = new DeflaterOutputStream(out);
|
||||||
|
try {
|
||||||
|
deflaterInputStream.write(buffer.array());
|
||||||
|
deflaterInputStream.flush();
|
||||||
|
deflaterInputStream.close();
|
||||||
|
//write to disk
|
||||||
|
FileUtils.saveBinaryToSavePath(Globals.currentSaveName, fileName, out.toByteArray());
|
||||||
|
//save to the map of filenames
|
||||||
|
worldPosFileMap.put(chunkKey,fileName);
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
package electrosphere.server.fluid.generation;
|
||||||
|
|
||||||
|
import electrosphere.server.fluid.manager.ServerFluidChunk;
|
||||||
|
import electrosphere.server.fluid.models.FluidModel;
|
||||||
|
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
|
||||||
|
public class ArenaFluidGenerator implements FluidGenerator {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServerFluidChunk generateChunk(int worldX, int worldY, int worldZ) {
|
||||||
|
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
|
||||||
|
float[][][] velocityX = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
|
||||||
|
float[][][] velocityY = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
|
||||||
|
float[][][] velocityZ = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
|
||||||
|
ServerFluidChunk chunk = new ServerFluidChunk(worldX, worldY, worldZ, weights, velocityX, velocityY, velocityZ);
|
||||||
|
|
||||||
|
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[3][3][3] = 0.8f;
|
||||||
|
return chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setModel(FluidModel model) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'setModel'");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package electrosphere.server.fluid.generation;
|
||||||
|
|
||||||
|
import electrosphere.server.fluid.manager.ServerFluidChunk;
|
||||||
|
import electrosphere.server.fluid.models.FluidModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates fluid
|
||||||
|
*/
|
||||||
|
public interface FluidGenerator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a chunk given an x, y, and z
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return The chunk
|
||||||
|
*/
|
||||||
|
public ServerFluidChunk generateChunk(int worldX, int worldY, int worldZ);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the fluid model for the generation algorithm
|
||||||
|
* @param model The fluid model
|
||||||
|
*/
|
||||||
|
public void setModel(FluidModel model);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
package electrosphere.server.fluid.manager;
|
||||||
|
|
||||||
|
|
||||||
|
import org.joml.Vector3f;
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is a single chunk of terrain on the server
|
||||||
|
*/
|
||||||
|
public class ServerFluidChunk {
|
||||||
|
|
||||||
|
|
||||||
|
int worldX, worldY, worldZ;
|
||||||
|
float[][][] weights;
|
||||||
|
float[][][] velocityX;
|
||||||
|
float[][][] velocityY;
|
||||||
|
float[][][] velocityZ;
|
||||||
|
|
||||||
|
public ServerFluidChunk(
|
||||||
|
int worldX,
|
||||||
|
int worldY,
|
||||||
|
int worldZ,
|
||||||
|
float[][][] weights,
|
||||||
|
float[][][] velocityX,
|
||||||
|
float[][][] velocityY,
|
||||||
|
float[][][] velocityZ
|
||||||
|
) {
|
||||||
|
this.worldX = worldX;
|
||||||
|
this.worldY = worldY;
|
||||||
|
this.worldZ = worldZ;
|
||||||
|
this.weights = weights;
|
||||||
|
this.velocityX = velocityX;
|
||||||
|
this.velocityY = velocityY;
|
||||||
|
this.velocityZ = velocityZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldX() {
|
||||||
|
return worldX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldY() {
|
||||||
|
return worldY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldZ() {
|
||||||
|
return worldZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the world position of this terrain chunk as a joml Vector
|
||||||
|
* @return The vector
|
||||||
|
*/
|
||||||
|
public Vector3i getWorldPosition(){
|
||||||
|
return new Vector3i(worldX,worldY,worldZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[][][] getWeights() {
|
||||||
|
return weights;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the weight of a voxel at a poisiton
|
||||||
|
* @param localPosition The local position
|
||||||
|
* @return The weight of the specified voxel
|
||||||
|
*/
|
||||||
|
public float getWeight(Vector3i localPosition){
|
||||||
|
return getWeight(localPosition.x,localPosition.y,localPosition.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the weight of a voxel at a poisiton
|
||||||
|
* @param x The x coordinate
|
||||||
|
* @param y The y coordinate
|
||||||
|
* @param z The z coordinate
|
||||||
|
* @return The weight of the specified voxel
|
||||||
|
*/
|
||||||
|
public float getWeight(int x, int y, int z){
|
||||||
|
return weights[x][y][z];
|
||||||
|
}
|
||||||
|
|
||||||
|
//get velocity x
|
||||||
|
public float[][][] getVelocityX() {
|
||||||
|
return velocityX;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//set velocity x
|
||||||
|
public void setVelocityX(float[][][] velocityX) {
|
||||||
|
this.velocityX = velocityX;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get velocity y
|
||||||
|
public float[][][] getVelocityY() {
|
||||||
|
return velocityY;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set velocity y
|
||||||
|
public void setVelocityY(float[][][] velocityY) {
|
||||||
|
this.velocityY = velocityY;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//get velocity z
|
||||||
|
public float[][][] getVelocityZ() {
|
||||||
|
return velocityZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//set velocity z
|
||||||
|
public void setVelocityZ(float[][][] velocityZ) {
|
||||||
|
this.velocityZ = velocityZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
//get a velocity at a given x, y and z as a Vector3f
|
||||||
|
public Vector3f getVelocity(int x, int y, int z){
|
||||||
|
return new Vector3f(velocityX[x][y][z],velocityY[x][y][z],velocityZ[x][y][z]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//set a velocity at a given x, y, and z given three ints
|
||||||
|
public void setVelocity(int x, int y, int z, float velX, float velY, float velZ){
|
||||||
|
velocityX[x][y][z] = velX;
|
||||||
|
velocityY[x][y][z] = velY;
|
||||||
|
velocityZ[x][y][z] = velZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,284 @@
|
|||||||
|
package electrosphere.server.fluid.manager;
|
||||||
|
|
||||||
|
|
||||||
|
import electrosphere.engine.Globals;
|
||||||
|
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.util.FileUtils;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
import org.joml.Vector3i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides an interface for the server to query information about fluid
|
||||||
|
*/
|
||||||
|
public class ServerFluidManager {
|
||||||
|
|
||||||
|
//The size of the world in discrete units * must be multiple of 200
|
||||||
|
int worldSizeDiscrete;
|
||||||
|
|
||||||
|
//The vertical multiplier applied to the statically generated fluid
|
||||||
|
int verticalInterpolationRatio;
|
||||||
|
|
||||||
|
float interpolationRandomDampener;
|
||||||
|
|
||||||
|
long seed;
|
||||||
|
|
||||||
|
//The model of the fluid this manager is managing
|
||||||
|
FluidModel model;
|
||||||
|
|
||||||
|
|
||||||
|
//In memory cache of chunk data
|
||||||
|
//Basic idea is we associate string that contains chunk x&y&z with elevation
|
||||||
|
//While we incur a penalty with converting ints -> string, think this will
|
||||||
|
//offset regenerating the array every time we want a new one
|
||||||
|
int cacheSize = 500;
|
||||||
|
Map<String, ServerFluidChunk> chunkCache;
|
||||||
|
List<String> chunkCacheContents;
|
||||||
|
|
||||||
|
//The map of chunk position <-> file on disk containing chunk data
|
||||||
|
FluidDiskMap chunkDiskMap = null;
|
||||||
|
|
||||||
|
//The generation algorithm for this fluid manager
|
||||||
|
FluidGenerator chunkGenerator;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public ServerFluidManager(
|
||||||
|
int worldSizeDiscrete,
|
||||||
|
int verticalInterpolationRatio,
|
||||||
|
float interpolationRandomDampener,
|
||||||
|
long seed,
|
||||||
|
FluidGenerator chunkGenerator
|
||||||
|
){
|
||||||
|
this.worldSizeDiscrete = worldSizeDiscrete;
|
||||||
|
this.verticalInterpolationRatio = verticalInterpolationRatio;
|
||||||
|
this.chunkCache = new ConcurrentHashMap<String, ServerFluidChunk>();
|
||||||
|
this.chunkCacheContents = new CopyOnWriteArrayList<String>();
|
||||||
|
this.interpolationRandomDampener = interpolationRandomDampener;
|
||||||
|
this.seed = seed;
|
||||||
|
this.chunkGenerator = chunkGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerFluidManager(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an arena fluid manager
|
||||||
|
* @return The arena fluid manager
|
||||||
|
*/
|
||||||
|
public static ServerFluidManager constructArenaFluidManager(){
|
||||||
|
ServerFluidManager rVal = new ServerFluidManager();
|
||||||
|
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();
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a fluid model for the manager
|
||||||
|
*/
|
||||||
|
public void generate(){
|
||||||
|
// FluidGenerator terrainGen = new FluidGenerator();
|
||||||
|
// terrainGen.setInterpolationRatio(worldSizeDiscrete/200);
|
||||||
|
// terrainGen.setVerticalInterpolationRatio(verticalInterpolationRatio);
|
||||||
|
// terrainGen.setRandomSeed(seed);
|
||||||
|
// model = terrainGen.generateModel();
|
||||||
|
// this.chunkGenerator.setModel(model);
|
||||||
|
// model.setInterpolationRandomDampener(interpolationRandomDampener);
|
||||||
|
// this.chunkDiskMap = new ChunkDiskMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the fluid model backing this manager to a save file
|
||||||
|
* @param saveName The name of the save
|
||||||
|
*/
|
||||||
|
public void save(String saveName){
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(model.getElevation().length * model.getElevation()[0].length * 4);
|
||||||
|
FloatBuffer floatView = buffer.asFloatBuffer();
|
||||||
|
for(int x = 0; x < model.getElevation().length; x++){
|
||||||
|
floatView.put(model.getElevation()[x]);
|
||||||
|
}
|
||||||
|
floatView.flip();
|
||||||
|
FileUtils.saveBinaryToSavePath(saveName, "./fluid.dat", buffer.array());
|
||||||
|
FileUtils.serializeObjectToSavePath(saveName, "./fluid.json", model);
|
||||||
|
//for each chunk, save via disk map
|
||||||
|
for(String chunkKey : chunkCacheContents){
|
||||||
|
ServerFluidChunk chunk = chunkCache.get(chunkKey);
|
||||||
|
chunkDiskMap.saveToDisk(chunk);
|
||||||
|
}
|
||||||
|
//save disk map itself
|
||||||
|
if(chunkDiskMap != null){
|
||||||
|
chunkDiskMap.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a fluid manager from a save file
|
||||||
|
* @param saveName The name of the save
|
||||||
|
*/
|
||||||
|
public void load(String saveName){
|
||||||
|
//load fluid model
|
||||||
|
model = FileUtils.loadObjectFromSavePath(saveName, "./fluid.json", FluidModel.class);
|
||||||
|
chunkGenerator.setModel(model);
|
||||||
|
byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./fluid.dat");
|
||||||
|
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||||
|
FloatBuffer floatView = buffer.asFloatBuffer();
|
||||||
|
float[][] elevation = new float[Globals.serverWorldData.getWorldSizeDiscrete()][Globals.serverWorldData.getWorldSizeDiscrete()];
|
||||||
|
for(int x = 0; x < Globals.serverWorldData.getWorldSizeDiscrete(); x++){
|
||||||
|
for(int y = 0; y < Globals.serverWorldData.getWorldSizeDiscrete(); y++){
|
||||||
|
elevation[x][y] = floatView.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
model.setElevationArray(elevation);
|
||||||
|
//load chunk disk map
|
||||||
|
chunkDiskMap = new FluidDiskMap();
|
||||||
|
chunkDiskMap.init(saveName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[][] getFluidAtChunk(int x, int y){
|
||||||
|
return model.getElevationForChunk(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getHeightAtPosition(double x, double y, double z){
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWorldDiscreteSize(){
|
||||||
|
return worldSizeDiscrete;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDiscreteValue(int x, int y){
|
||||||
|
if(model != null){
|
||||||
|
return model.getElevation()[x][y];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDynamicInterpolationRatio(){
|
||||||
|
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
|
||||||
|
if(model != null){
|
||||||
|
return model.getDynamicInterpolationRatio();
|
||||||
|
} else {
|
||||||
|
//THIS FIRES IF THERE IS AN ARENA WORLD RUNNING
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRandomDampener(){
|
||||||
|
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
|
||||||
|
if(model != null){
|
||||||
|
return model.getRandomDampener();
|
||||||
|
} else {
|
||||||
|
//THIS FIRES IF THERE IS AN ARENA WORLD RUNNING
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the fluid model backing this fluid manager
|
||||||
|
* @return The fluid model
|
||||||
|
*/
|
||||||
|
public FluidModel getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the key for a given world position
|
||||||
|
* @param worldX The x component
|
||||||
|
* @param worldY The y component
|
||||||
|
* @param worldZ The z component
|
||||||
|
* @return The key
|
||||||
|
*/
|
||||||
|
public String getKey(int worldX, int worldY, int worldZ){
|
||||||
|
return worldX + "_" + worldY + "_" + worldZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a server fluid chunk
|
||||||
|
* @param worldX The world x position
|
||||||
|
* @param worldY The world y position
|
||||||
|
* @param worldZ The world z position
|
||||||
|
* @return The ServerFluidChunk
|
||||||
|
*/
|
||||||
|
public ServerFluidChunk getChunk(int worldX, int worldY, int worldZ){
|
||||||
|
//THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
|
||||||
|
String key = getKey(worldX,worldY,worldZ);
|
||||||
|
ServerFluidChunk returnedChunk = null;
|
||||||
|
if(chunkCache.containsKey(key)){
|
||||||
|
chunkCacheContents.remove(key);
|
||||||
|
chunkCacheContents.add(0, key);
|
||||||
|
returnedChunk = chunkCache.get(key);
|
||||||
|
return returnedChunk;
|
||||||
|
} else {
|
||||||
|
if(chunkCacheContents.size() > cacheSize){
|
||||||
|
String oldChunk = chunkCacheContents.remove(chunkCacheContents.size() - 1);
|
||||||
|
chunkCache.remove(oldChunk);
|
||||||
|
}
|
||||||
|
//pull from disk if it exists
|
||||||
|
if(chunkDiskMap != null){
|
||||||
|
if(chunkDiskMap.containsFluidAtPosition(worldX, worldY, worldZ)){
|
||||||
|
returnedChunk = chunkDiskMap.getFluidChunk(worldX, worldY, worldZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//generate if it does not exist
|
||||||
|
if(returnedChunk == null){
|
||||||
|
returnedChunk = chunkGenerator.generateChunk(worldX, worldY, worldZ);
|
||||||
|
}
|
||||||
|
chunkCache.put(key, returnedChunk);
|
||||||
|
chunkCacheContents.add(key);
|
||||||
|
return returnedChunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a given position's chunk to disk.
|
||||||
|
* Uses the current global save name
|
||||||
|
* @param position The position to save
|
||||||
|
*/
|
||||||
|
public void savePositionToDisk(Vector3i position){
|
||||||
|
chunkDiskMap.saveToDisk(getChunk(position.x, position.y, position.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a deform to fluid at a given location
|
||||||
|
* @param worldPos The world coordinates of the chunk to modify
|
||||||
|
* @param voxelPos The voxel coordinates of the voxel to modify
|
||||||
|
* @param weight The weight to set it to
|
||||||
|
* @param value The value to set it to
|
||||||
|
*/
|
||||||
|
public void deformFluidAtLocationToValue(Vector3i worldPos, Vector3i voxelPos, float weight, int value){
|
||||||
|
// TerrainModification modification = new TerrainModification(worldPos,voxelPos,weight,value);
|
||||||
|
// //could be null if, for instance, arena mode
|
||||||
|
// if(model != null){
|
||||||
|
// model.addModification(modification);
|
||||||
|
// }
|
||||||
|
// String key = getKey(worldPos.x,worldPos.y,worldPos.z);
|
||||||
|
// if(chunkCache.containsKey(key)){
|
||||||
|
// ServerFluidChunk chunk = chunkCache.get(key);
|
||||||
|
// chunk.addModification(modification);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simulates all active fluid chunks
|
||||||
|
*/
|
||||||
|
public void simulate(){
|
||||||
|
//TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
343
src/main/java/electrosphere/server/fluid/models/FluidModel.java
Normal file
343
src/main/java/electrosphere/server/fluid/models/FluidModel.java
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
package electrosphere.server.fluid.models;
|
||||||
|
|
||||||
|
import electrosphere.util.annotation.Exclude;
|
||||||
|
|
||||||
|
public class FluidModel {
|
||||||
|
|
||||||
|
int dynamicInterpolationRatio;
|
||||||
|
float interpolationRandomDampener = 0.4f;
|
||||||
|
|
||||||
|
int discreteArrayDimension;
|
||||||
|
@Exclude
|
||||||
|
private float[][] elevation;
|
||||||
|
|
||||||
|
float realMountainThreshold;
|
||||||
|
float realOceanThreshold;
|
||||||
|
|
||||||
|
FluidModel() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidModel(
|
||||||
|
int dimension,
|
||||||
|
int dynamicInterpolationRatio
|
||||||
|
){
|
||||||
|
|
||||||
|
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
|
||||||
|
this.discreteArrayDimension = dimension;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FluidModel constructFluidModel(int dimension, int dynamicInterpolationRatio){
|
||||||
|
FluidModel rVal = new FluidModel();
|
||||||
|
rVal.discreteArrayDimension = dimension;
|
||||||
|
rVal.dynamicInterpolationRatio = dynamicInterpolationRatio;
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[][] getElevation(){
|
||||||
|
return elevation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInterpolationRandomDampener(float f){
|
||||||
|
interpolationRandomDampener = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamically interpolates a chunk of a specific size from the pre-existing elevation map
|
||||||
|
* @param x The x position on the elevation map to get a chunk from
|
||||||
|
* @param y The y position on the elevation map to get a chunk from
|
||||||
|
* @return Dynamically interpolated float array of elevations of chunk
|
||||||
|
*/
|
||||||
|
public float[][] getElevationForChunk(int x, int y){
|
||||||
|
|
||||||
|
//this is what we intend to return from the function
|
||||||
|
float[][] rVal = new float[dynamicInterpolationRatio][dynamicInterpolationRatio];
|
||||||
|
|
||||||
|
/*
|
||||||
|
So we're looking at chunk x,y
|
||||||
|
|
||||||
|
if this is our grid:
|
||||||
|
|
||||||
|
4 0.1 0.2 0.3 0.4
|
||||||
|
^
|
||||||
|
| 3 0.1 0.2 0.3 0.4
|
||||||
|
|
|
||||||
|
| 2 0.1 0.2 0.3 0.4
|
||||||
|
|
||||||
|
x 1 0.1 0.2 0.3 0.4
|
||||||
|
|
||||||
|
0 1 2 3
|
||||||
|
|
||||||
|
y ---- >
|
||||||
|
|
||||||
|
say we're looking at x=2,y=1
|
||||||
|
|
||||||
|
"macroValues" should contain the values for bounds x = [1,3] and y = [0,2]
|
||||||
|
|
||||||
|
the goal is to have the "center" of the output chunk have the value the
|
||||||
|
elevation grid at x=2,y=1
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//set macroValues
|
||||||
|
float[][] macroValues = getMacroValuesAtPosition(x,y);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int halfLength = dynamicInterpolationRatio/2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Four quadrants we're generating
|
||||||
|
|
||||||
|
_____________________
|
||||||
|
|1 |2 |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
|__________|__________|
|
||||||
|
|3 |4 |
|
||||||
|
| | |
|
||||||
|
| | |
|
||||||
|
|__________|__________|
|
||||||
|
|
||||||
|
First set of loops is quadrant 1
|
||||||
|
then quadrant 2
|
||||||
|
then quadrant 3
|
||||||
|
then quadrant 4
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
int outXOffset = 0;
|
||||||
|
int outYOffset = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < halfLength; i++){
|
||||||
|
for(int j = 0; j < halfLength; j++){
|
||||||
|
rVal[i+outXOffset][j+outYOffset] =
|
||||||
|
(1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[0][0] +
|
||||||
|
(1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][0] +
|
||||||
|
(1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[0][1] +
|
||||||
|
(1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][1]
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outXOffset = halfLength;
|
||||||
|
for(int i = 0; i < halfLength; i++){
|
||||||
|
for(int j = 0; j < halfLength; j++){
|
||||||
|
rVal[i+outXOffset][j+outYOffset] =
|
||||||
|
(1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][0] +
|
||||||
|
(1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[2][0] +
|
||||||
|
(1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][1] +
|
||||||
|
(1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[2][1]
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outXOffset = 0;
|
||||||
|
outYOffset = halfLength;
|
||||||
|
for(int i = 0; i < halfLength; i++){
|
||||||
|
for(int j = 0; j < halfLength; j++){
|
||||||
|
rVal[i+outXOffset][j+outYOffset] =
|
||||||
|
(1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[0][1] +
|
||||||
|
(1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][1] +
|
||||||
|
(1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[0][2] +
|
||||||
|
(1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][2]
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outXOffset = halfLength;
|
||||||
|
for(int i = 0; i < halfLength; i++){
|
||||||
|
for(int j = 0; j < halfLength; j++){
|
||||||
|
rVal[i+outXOffset][j+outYOffset] =
|
||||||
|
(1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][1] +
|
||||||
|
(1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[2][1] +
|
||||||
|
(1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][2] +
|
||||||
|
(1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[2][2]
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
So we're looking at chunk x,y
|
||||||
|
|
||||||
|
if this is our grid:
|
||||||
|
|
||||||
|
4 0.1 0.2 0.3 0.4
|
||||||
|
^
|
||||||
|
| 3 0.1 0.2 0.3 0.4
|
||||||
|
|
|
||||||
|
| 2 0.1 0.2 0.3 0.4
|
||||||
|
|
||||||
|
x 1 0.1 0.2 0.3 0.4
|
||||||
|
|
||||||
|
0 1 2 3
|
||||||
|
|
||||||
|
y ---- >
|
||||||
|
|
||||||
|
say we're looking at x=2,y=1
|
||||||
|
|
||||||
|
"macroValues" should contain the values for x = [1,3] and y = [0,2]
|
||||||
|
|
||||||
|
the goal is to have the "center" of the output chunk have the value the
|
||||||
|
elevation grid at x=2,y=1
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
public float[][] getMacroValuesAtPosition(int x, int y){
|
||||||
|
|
||||||
|
float[][] rVal = new float[3][3];
|
||||||
|
rVal[1][1] = elevation[x][y];
|
||||||
|
if(x - 1 >= 0){
|
||||||
|
rVal[0][1] = elevation[x-1][y];
|
||||||
|
if(y - 1 >= 0){
|
||||||
|
rVal[0][0] = elevation[x-1][y-1];
|
||||||
|
} else {
|
||||||
|
rVal[0][0] = 0;
|
||||||
|
}
|
||||||
|
if(y + 1 < discreteArrayDimension){
|
||||||
|
rVal[0][2] = elevation[x-1][y+1];
|
||||||
|
} else {
|
||||||
|
rVal[0][2] = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rVal[0][0] = 0;
|
||||||
|
rVal[0][1] = 0;
|
||||||
|
rVal[0][2] = 0;
|
||||||
|
}
|
||||||
|
if(x + 1 < discreteArrayDimension){
|
||||||
|
rVal[2][1] = elevation[x+1][y];
|
||||||
|
if(y - 1 >= 0){
|
||||||
|
rVal[2][0] = elevation[x+1][y-1];
|
||||||
|
} else {
|
||||||
|
rVal[2][0] = 0;
|
||||||
|
}
|
||||||
|
if(y + 1 < discreteArrayDimension){
|
||||||
|
rVal[2][2] = elevation[x+1][y+1];
|
||||||
|
} else {
|
||||||
|
rVal[2][2] = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rVal[2][0] = 0;
|
||||||
|
rVal[2][1] = 0;
|
||||||
|
rVal[2][2] = 0;
|
||||||
|
}
|
||||||
|
if(y - 1 >= 0){
|
||||||
|
rVal[1][0] = elevation[x][y-1];
|
||||||
|
} else {
|
||||||
|
rVal[1][0] = 0;
|
||||||
|
}
|
||||||
|
if(y + 1 < discreteArrayDimension){
|
||||||
|
rVal[1][2] = elevation[x][y+1];
|
||||||
|
} else {
|
||||||
|
rVal[1][2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public float[][] getRad5MacroValuesAtPosition(int x, int y){
|
||||||
|
|
||||||
|
float[][] rVal = new float[5][5];
|
||||||
|
for(int i = -2; i < 3; i++){
|
||||||
|
for(int j = -2; j < 3; j++){
|
||||||
|
if(x + i >= 0 && x + i < discreteArrayDimension && y + j >= 0 && y + j < discreteArrayDimension){
|
||||||
|
rVal[i+2][j+2] = elevation[x+i][y+j];
|
||||||
|
} else {
|
||||||
|
rVal[i+2][j+2] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
So we're looking at chunk x,y
|
||||||
|
|
||||||
|
if this is our grid:
|
||||||
|
|
||||||
|
4 0.1 0.2 0.3 0.4
|
||||||
|
^
|
||||||
|
| 3 0.1 0.2 0.3 0.4
|
||||||
|
|
|
||||||
|
| 2 0.1 0.2 0.3 0.4
|
||||||
|
|
||||||
|
x 1 0.1 0.2 0.3 0.4
|
||||||
|
|
||||||
|
0 1 2 3
|
||||||
|
|
||||||
|
y ---- >
|
||||||
|
|
||||||
|
say we're looking at x=2,y=1
|
||||||
|
|
||||||
|
"macroValues" should contain the values for x = [1,3] and y = [0,2]
|
||||||
|
|
||||||
|
the goal is to have the "center" of the output chunk have the value the
|
||||||
|
elevation grid at x=2,y=1
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public float getRandomDampener(){
|
||||||
|
return interpolationRandomDampener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDynamicInterpolationRatio(){
|
||||||
|
return dynamicInterpolationRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRealMountainThreshold() {
|
||||||
|
return realMountainThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRealOceanThreshold() {
|
||||||
|
return realOceanThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModificationKey(int x, int y, int z){
|
||||||
|
return x + "_" + y + "_" + z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void addModification(TerrainModification modification){
|
||||||
|
// String key = getModificationKey(modification.getWorldPos().x,modification.getWorldPos().y,modification.getWorldPos().z);
|
||||||
|
// ModificationList list;
|
||||||
|
// if(!modifications.containsKey(key)){
|
||||||
|
// list = new ModificationList();
|
||||||
|
// modifications.put(key, list);
|
||||||
|
// } else {
|
||||||
|
// list = modifications.get(key);
|
||||||
|
// }
|
||||||
|
// list.addModification(modification);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public boolean containsModificationsAtCoord(int worldX, int worldY, int worldZ){
|
||||||
|
// return modifications.containsKey(getModificationKey(worldX, worldY, worldZ));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public ModificationList getModifications(int worldX, int worldY, int worldZ){
|
||||||
|
// // System.out.println("Got modifications at " + worldX + " " + worldY);
|
||||||
|
// return modifications.get(getModificationKey(worldX, worldY, worldZ));
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the elevation array (For instance when read from save file on loading a save)
|
||||||
|
* @param elevation The elevation array to set to
|
||||||
|
*/
|
||||||
|
public void setElevationArray(float[][] elevation){
|
||||||
|
this.elevation = elevation;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user