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
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
@ -196,6 +196,10 @@ Transvoxel Algorithm
|
||||
- Prebake all textures into 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
|
||||
- Could potentially be held at actor level
|
||||
- Link different models based on LOD level
|
||||
|
||||
@ -184,6 +184,23 @@
|
||||
"worldZ",
|
||||
"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.types.attach.AttachUtils;
|
||||
|
||||
@Deprecated
|
||||
public class ClientEntityCullingManager {
|
||||
|
||||
Scene scene;
|
||||
@ -40,38 +41,4 @@ public class ClientEntityCullingManager {
|
||||
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
|
||||
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
|
||||
float[][][] voxelWeight;
|
||||
|
||||
//The velocities
|
||||
float[][][] velocityX;
|
||||
float[][][] velocityY;
|
||||
float[][][] velocityZ;
|
||||
|
||||
//the list of positions modified since the last call to resetModifiedPositions
|
||||
//Used in DrawCell to keep track of which positions to invalidate
|
||||
Set<String> modifiedSinceLastGeneration = new HashSet<String>();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the voxel 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
|
||||
* @return The voxel weight array
|
||||
@ -91,23 +62,23 @@ public class FluidChunkData {
|
||||
this.voxelWeight = voxelWeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value of a single voxel in the chunk
|
||||
* @param localX The local position X
|
||||
* @param localY The local position Y
|
||||
* @param localZ The local position Z
|
||||
* @param weight The weight to set it to
|
||||
* @param type The type to set the voxel to
|
||||
*/
|
||||
public void updatePosition(int localX, int localY, int localZ, float weight, int type){
|
||||
voxelWeight[localX][localY][localZ] = weight;
|
||||
voxelType[localX][localY][localZ] = type;
|
||||
//store as modified in cache
|
||||
String key = getVoxelPositionKey(new Vector3i(localX,localY,localZ));
|
||||
if(!modifiedSinceLastGeneration.contains(key)){
|
||||
modifiedSinceLastGeneration.add(key);
|
||||
}
|
||||
}
|
||||
// /**
|
||||
// * Updates the value of a single voxel in the chunk
|
||||
// * @param localX The local position X
|
||||
// * @param localY The local position Y
|
||||
// * @param localZ The local position Z
|
||||
// * @param weight The weight to set it to
|
||||
// * @param type The type to set the voxel to
|
||||
// */
|
||||
// public void updatePosition(int localX, int localY, int localZ, float weight, int type){
|
||||
// voxelWeight[localX][localY][localZ] = weight;
|
||||
// voxelType[localX][localY][localZ] = type;
|
||||
// //store as modified in cache
|
||||
// String key = getVoxelPositionKey(new Vector3i(localX,localY,localZ));
|
||||
// if(!modifiedSinceLastGeneration.contains(key)){
|
||||
// modifiedSinceLastGeneration.add(key);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Gets the weight of a voxel at a poisiton
|
||||
@ -119,12 +90,11 @@ public class FluidChunkData {
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of a voxel at a position
|
||||
* @param localPosition The local position
|
||||
* @return The type of the specified voxel
|
||||
* Gets the weight of a voxel at a poisiton
|
||||
* @return The weight of the specified voxel
|
||||
*/
|
||||
public int getType(Vector3i localPosition){
|
||||
return voxelType[localPosition.x][localPosition.y][localPosition.z];
|
||||
public float getWeight(int x, int y, int 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
|
||||
*/
|
||||
public class FluidDrawCellManager {
|
||||
public class FluidCellManager {
|
||||
|
||||
|
||||
//the center of this cell manager's array in cell space
|
||||
@ -35,8 +35,8 @@ public class FluidDrawCellManager {
|
||||
int miniCellWidth;
|
||||
|
||||
//all currently displaying mini cells
|
||||
Set<FluidDrawCell> cells;
|
||||
Map<String,FluidDrawCell> keyCellMap = new HashMap<String,FluidDrawCell>();
|
||||
Set<FluidCell> cells;
|
||||
Map<String,FluidCell> keyCellMap = new HashMap<String,FluidCell>();
|
||||
Set<String> hasNotRequested;
|
||||
Set<String> hasRequested;
|
||||
Set<String> drawable;
|
||||
@ -59,8 +59,6 @@ public class FluidDrawCellManager {
|
||||
int worldBoundDiscreteMin = 0;
|
||||
int worldBoundDiscreteMax = 0;
|
||||
|
||||
//client terrain manager
|
||||
// ClientTerrainManager clientTerrainManager;
|
||||
|
||||
|
||||
//ready to start updating?
|
||||
@ -78,9 +76,9 @@ public class FluidDrawCellManager {
|
||||
* @param discreteX The initial discrete position X 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);
|
||||
cells = new HashSet<FluidDrawCell>();
|
||||
cells = new HashSet<FluidCell>();
|
||||
hasNotRequested = new HashSet<String>();
|
||||
drawable = new HashSet<String>();
|
||||
undrawable = new HashSet<String>();
|
||||
@ -102,7 +100,7 @@ public class FluidDrawCellManager {
|
||||
update = true;
|
||||
}
|
||||
|
||||
FluidDrawCellManager(){
|
||||
FluidCellManager(){
|
||||
|
||||
}
|
||||
|
||||
@ -132,7 +130,7 @@ public class FluidDrawCellManager {
|
||||
){
|
||||
// if(!hasRequested.contains(targetKey)){
|
||||
//client should request chunk data from server
|
||||
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestChunkDataMessage(
|
||||
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestFluidDataMessage(
|
||||
worldPos.x,
|
||||
worldPos.y,
|
||||
worldPos.z
|
||||
@ -161,7 +159,7 @@ public class FluidDrawCellManager {
|
||||
worldPos.z < Globals.clientWorldData.getWorldDiscreteSize()
|
||||
){
|
||||
if(containsChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z)){
|
||||
FluidDrawCell cell = FluidDrawCell.generateFluidCell(
|
||||
FluidCell cell = FluidCell.generateFluidCell(
|
||||
worldPos,
|
||||
Globals.clientFluidManager.getChunkDataAtWorldPoint(worldPos.x, worldPos.y, worldPos.z),
|
||||
program
|
||||
@ -256,14 +254,14 @@ public class FluidDrawCellManager {
|
||||
* Clears all cells outside of draw radius
|
||||
*/
|
||||
private void clearOutOfBoundsCells(){
|
||||
Set<FluidDrawCell> cellsToRemove = new HashSet<FluidDrawCell>();
|
||||
for(FluidDrawCell cell : cells){
|
||||
Set<FluidCell> cellsToRemove = new HashSet<FluidCell>();
|
||||
for(FluidCell cell : cells){
|
||||
Vector3d realPos = cell.getRealPos();
|
||||
if(Globals.playerEntity != null && EntityUtils.getPosition(Globals.playerEntity).distance(realPos) > drawRadius){
|
||||
cellsToRemove.add(cell);
|
||||
}
|
||||
}
|
||||
for(FluidDrawCell cell : cellsToRemove){
|
||||
for(FluidCell cell : cellsToRemove){
|
||||
cells.remove(cell);
|
||||
String key = getCellKey(cell.worldPos.x, cell.worldPos.y, cell.worldPos.z);
|
||||
hasNotRequested.remove(key);
|
||||
@ -358,8 +356,8 @@ public class FluidDrawCellManager {
|
||||
}
|
||||
|
||||
boolean containsChunkDataAtWorldPoint(int worldX, int worldY, int worldZ){
|
||||
if(Globals.clientTerrainManager != null){
|
||||
return Globals.clientTerrainManager.containsChunkDataAtWorldPoint(worldX,worldY,worldZ);
|
||||
if(Globals.clientFluidManager != null){
|
||||
return Globals.clientFluidManager.containsChunkDataAtWorldPoint(worldX,worldY,worldZ);
|
||||
}
|
||||
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){
|
||||
messageQueue.remove(message);
|
||||
switch(message.getMessageSubtype()){
|
||||
case SENDCHUNKDATA: {
|
||||
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_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_SIZE][FluidChunkData.CHUNK_DATA_GENERATOR_SIZE];
|
||||
case SENDFLUIDDATA: {
|
||||
float[][][] weights = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
|
||||
float[][][] velocityX = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
|
||||
float[][][] velocityY = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
|
||||
float[][][] velocityZ = new float[FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE][FluidChunkData.CHUNK_SIZE];
|
||||
ByteBuffer buffer = ByteBuffer.wrap(message.getchunkData());
|
||||
FloatBuffer floatBuffer = buffer.asFloatBuffer();
|
||||
for(int x = 0; x < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){
|
||||
for(int y = 0; y < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){
|
||||
for(int z = 0; z < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; z++){
|
||||
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
|
||||
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
|
||||
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
|
||||
weights[x][y][z] = floatBuffer.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
IntBuffer intView = buffer.asIntBuffer();
|
||||
intView.position(floatBuffer.position());
|
||||
for(int x = 0; x < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; x++){
|
||||
for(int y = 0; y < FluidChunkData.CHUNK_DATA_GENERATOR_SIZE; y++){
|
||||
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++){
|
||||
velocityX[x][y][z] = floatBuffer.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
|
||||
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
|
||||
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
|
||||
velocityY[x][y][z] = floatBuffer.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
for(int x = 0; x < FluidChunkData.CHUNK_SIZE; x++){
|
||||
for(int y = 0; y < FluidChunkData.CHUNK_SIZE; y++){
|
||||
for(int z = 0; z < FluidChunkData.CHUNK_SIZE; z++){
|
||||
velocityZ[x][y][z] = floatBuffer.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
FluidChunkData data = new FluidChunkData();
|
||||
data.setVoxelType(values);
|
||||
data.setVoxelWeight(weights);
|
||||
fluidCache.addChunkDataToCache(
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -311,7 +311,6 @@ public class ClientFoliageManager {
|
||||
* @param voxelPos The voxel position
|
||||
*/
|
||||
private void createFoliageCell(Vector3i worldPos, Vector3i voxelPos, float initialGrowthLevel){
|
||||
System.out.println("Create foliage cell");
|
||||
//get foliage types supported
|
||||
ChunkData data = Globals.clientTerrainManager.getChunkDataAtWorldPoint(worldPos);
|
||||
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_21 = (float)(sample_21 != null ? sample_21.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
|
||||
//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
|
||||
@ -375,15 +369,6 @@ public class ClientFoliageManager {
|
||||
double offsetZ = relativePositionOnGridZ;
|
||||
//determine quadrant we're placing in
|
||||
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;
|
||||
if(relativePositionOnGridX >=0){
|
||||
if(relativePositionOnGridZ >= 0){
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package electrosphere.client.sim;
|
||||
|
||||
import electrosphere.client.fluid.manager.ClientFluidManager;
|
||||
import electrosphere.client.instancing.InstanceUpdater;
|
||||
import electrosphere.client.terrain.manager.ClientTerrainManager;
|
||||
import electrosphere.engine.Globals;
|
||||
@ -27,6 +28,7 @@ public class ClientFunctions {
|
||||
|
||||
public static void runClientFunctions(){
|
||||
ClientTerrainManager.generateTerrainChunkGeometry();
|
||||
ClientFluidManager.generateFluidChunkGeometry();
|
||||
updateSkyboxPos();
|
||||
Globals.clientSceneWrapper.destroyEntitiesOutsideSimRange();
|
||||
InstanceUpdater.updateInstancedActorPriority();
|
||||
@ -48,11 +50,15 @@ public class ClientFunctions {
|
||||
public static void loadTerrain(){
|
||||
if(Globals.clientTerrainManager != null){
|
||||
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
|
||||
///
|
||||
@ -65,4 +71,15 @@ public class ClientFunctions {
|
||||
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.auth.AuthenticationManager;
|
||||
import electrosphere.client.culling.ClientEntityCullingManager;
|
||||
import electrosphere.client.fluid.cells.FluidCellManager;
|
||||
import electrosphere.client.fluid.manager.ClientFluidManager;
|
||||
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
||||
import electrosphere.client.player.ClientPlayerData;
|
||||
@ -52,6 +53,7 @@ import electrosphere.renderer.actor.instance.InstanceManager;
|
||||
import electrosphere.renderer.light.PointLight;
|
||||
import electrosphere.renderer.light.SpotLight;
|
||||
import electrosphere.renderer.loading.ModelPretransforms;
|
||||
import electrosphere.renderer.meshgen.FluidChunkModelGeneration;
|
||||
import electrosphere.renderer.meshgen.TerrainChunkModelGeneration;
|
||||
import electrosphere.renderer.model.Material;
|
||||
import electrosphere.renderer.shader.ShaderOptionMap;
|
||||
@ -66,6 +68,7 @@ import electrosphere.server.content.ServerContentManager;
|
||||
import electrosphere.server.datacell.EntityDataCellMapper;
|
||||
import electrosphere.server.datacell.RealmManager;
|
||||
import electrosphere.server.db.DatabaseController;
|
||||
import electrosphere.server.fluid.manager.ServerFluidManager;
|
||||
import electrosphere.server.pathfinding.NavMeshManager;
|
||||
import electrosphere.server.simulation.MacroSimulation;
|
||||
import electrosphere.server.simulation.MicroSimulation;
|
||||
@ -254,6 +257,12 @@ public class Globals {
|
||||
//terrain manager
|
||||
// public static boolean LOAD_TERRAIN = true;
|
||||
public static ServerTerrainManager serverTerrainManager;
|
||||
|
||||
|
||||
//fluid manager
|
||||
public static ServerFluidManager serverFluidManager;
|
||||
|
||||
//spawn point
|
||||
public static Vector3d spawnPoint = new Vector3d(0,0,0);
|
||||
|
||||
//content manager
|
||||
@ -304,8 +313,11 @@ public class Globals {
|
||||
public static ClientPlayerData clientPlayerData = new ClientPlayerData();
|
||||
|
||||
//chunk stuff
|
||||
//constant for how far in game units you have to move to load chunks
|
||||
//draw cell manager
|
||||
public static DrawCellManager drawCellManager;
|
||||
|
||||
//fluid cell manager
|
||||
public static FluidCellManager fluidCellManager;
|
||||
|
||||
//navmesh manager
|
||||
public static NavMeshManager navMeshManager;
|
||||
@ -413,6 +425,8 @@ public class Globals {
|
||||
navMeshManager = new NavMeshManager();
|
||||
//terrain
|
||||
Globals.clientTerrainManager = new ClientTerrainManager();
|
||||
//fluid
|
||||
Globals.clientFluidManager = new ClientFluidManager();
|
||||
//game config
|
||||
gameConfigDefault = electrosphere.game.data.Config.loadDefaultConfig();
|
||||
gameConfigCurrent = gameConfigDefault;
|
||||
@ -471,8 +485,7 @@ public class Globals {
|
||||
terrainShaderProgram = 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
|
||||
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid1/fluid1.vs", "/Shaders/fluid1/fluid1.fs");
|
||||
TerrainChunkModelGeneration.terrainChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid1/fluid1.vs", "/Shaders/fluid1/fluid1.fs");
|
||||
FluidChunkModelGeneration.fluidChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid2/fluid2.vs", "/Shaders/fluid2/fluid2.fs");
|
||||
//init models
|
||||
assetManager.addModelPathToQueue("Models/unitsphere.fbx");
|
||||
assetManager.addModelPathToQueue("Models/unitsphere_1.fbx");
|
||||
|
||||
@ -15,6 +15,7 @@ import electrosphere.entity.ServerEntityUtils;
|
||||
import electrosphere.game.server.world.ServerWorldData;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.server.content.ServerContentManager;
|
||||
import electrosphere.server.fluid.manager.ServerFluidManager;
|
||||
import electrosphere.server.saves.SaveUtils;
|
||||
import electrosphere.server.terrain.manager.ServerTerrainManager;
|
||||
import electrosphere.util.FileUtils;
|
||||
@ -56,6 +57,7 @@ public class ArenaLoading {
|
||||
|
||||
private static void initServerArenaTerrainManager(){
|
||||
Globals.serverTerrainManager = ServerTerrainManager.constructArenaTerrainManager();
|
||||
Globals.serverFluidManager = ServerFluidManager.constructArenaFluidManager();
|
||||
}
|
||||
|
||||
private static void initServerArenaWorldData(){
|
||||
|
||||
@ -11,6 +11,7 @@ import electrosphere.audio.AudioUtils;
|
||||
import electrosphere.audio.VirtualAudioSource;
|
||||
import electrosphere.audio.VirtualAudioSourceManager.VirtualAudioSourceType;
|
||||
import electrosphere.client.culling.ClientEntityCullingManager;
|
||||
import electrosphere.client.fluid.cells.FluidCellManager;
|
||||
import electrosphere.client.foliagemanager.ClientFoliageManager;
|
||||
import electrosphere.client.sim.ClientSimulation;
|
||||
import electrosphere.client.targeting.crosshair.Crosshair;
|
||||
@ -93,6 +94,8 @@ public class ClientLoading {
|
||||
initFoliageManager();
|
||||
//initialize the cell manager (client)
|
||||
initDrawCellManager();
|
||||
//init the fluid cell manager
|
||||
initFluidCellManager();
|
||||
//initialize the basic graphical entities of the world (skybox, camera)
|
||||
initWorldBaseGraphicalEntities();
|
||||
//init arena specific stuff (ie different skybox colors)
|
||||
@ -290,6 +293,41 @@ public class ClientLoading {
|
||||
// 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
|
||||
*/
|
||||
|
||||
@ -17,9 +17,9 @@ public class FluidChunk {
|
||||
* @param values The values (block types)
|
||||
* @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);
|
||||
|
||||
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
|
||||
|
||||
@ -22,7 +22,7 @@ public class LoggerInterface {
|
||||
|
||||
public static void initLoggers(){
|
||||
loggerStartup = new Logger(LogLevel.WARNING);
|
||||
loggerNetworking = new Logger(LogLevel.WARNING);
|
||||
loggerNetworking = new Logger(LogLevel.DEBUG);
|
||||
loggerFileIO = new Logger(LogLevel.WARNING);
|
||||
loggerGameLogic = new Logger(LogLevel.WARNING);
|
||||
loggerRenderer = new Logger(LogLevel.WARNING);
|
||||
|
||||
@ -3,6 +3,7 @@ package electrosphere.net.client.protocol;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import electrosphere.client.fluid.cache.FluidChunkData;
|
||||
import electrosphere.client.scene.ClientWorldData;
|
||||
import electrosphere.client.terrain.cache.ChunkData;
|
||||
import electrosphere.collision.CollisionWorldData;
|
||||
@ -49,6 +50,9 @@ public class TerrainProtocol {
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case SENDFLUIDDATA: {
|
||||
Globals.clientFluidManager.attachFluidMessage(message);
|
||||
} break;
|
||||
default:
|
||||
LoggerInterface.loggerNetworking.WARNING("Client networking: Unhandled message of type: " + message.getMessageSubtype());
|
||||
break;
|
||||
|
||||
@ -236,6 +236,16 @@ SYNCHRONIZATION_MESSAGE,
|
||||
rVal = TerrainMessage.parsesendChunkDataMessage(byteBuffer);
|
||||
}
|
||||
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;
|
||||
case TypeBytes.MESSAGE_TYPE_SERVER:
|
||||
|
||||
@ -17,6 +17,8 @@ public class TerrainMessage extends NetworkMessage {
|
||||
SPAWNPOSITION,
|
||||
REQUESTCHUNKDATA,
|
||||
SENDCHUNKDATA,
|
||||
REQUESTFLUIDDATA,
|
||||
SENDFLUIDDATA,
|
||||
}
|
||||
|
||||
TerrainMessageType messageType;
|
||||
@ -266,6 +268,14 @@ public class TerrainMessage extends NetworkMessage {
|
||||
}
|
||||
case TypeBytes.TERRAIN_MESSAGE_TYPE_SENDCHUNKDATA:
|
||||
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;
|
||||
}
|
||||
@ -488,6 +498,72 @@ public class TerrainMessage extends NetworkMessage {
|
||||
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
|
||||
void serialize(){
|
||||
byte[] intValues = new byte[8];
|
||||
@ -718,6 +794,51 @@ public class TerrainMessage extends NetworkMessage {
|
||||
rawBytes[18+i] = chunkData[i];
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -88,6 +88,8 @@ Message categories
|
||||
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_SENDCHUNKDATA = 8;
|
||||
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA = 9;
|
||||
public static final byte TERRAIN_MESSAGE_TYPE_SENDFLUIDDATA = 10;
|
||||
/*
|
||||
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_SPAWNPOSITION_SIZE = 26;
|
||||
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNKDATA_SIZE = 14;
|
||||
public static final byte TERRAIN_MESSAGE_TYPE_REQUESTFLUIDDATA_SIZE = 14;
|
||||
/*
|
||||
Server subcategories
|
||||
*/
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package electrosphere.net.parser.net.raw;
|
||||
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.net.parser.net.message.NetworkMessage;
|
||||
package electrosphere.net.parser.net.raw;
|
||||
|
||||
import electrosphere.net.parser.net.message.NetworkMessage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@ -52,7 +51,7 @@ public class NetworkParser {
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
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.player.Player;
|
||||
import electrosphere.server.datacell.Realm;
|
||||
import electrosphere.server.fluid.manager.ServerFluidChunk;
|
||||
import electrosphere.server.terrain.editing.TerrainEditing;
|
||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||
import electrosphere.server.terrain.models.TerrainModification;
|
||||
@ -38,11 +39,17 @@ public class TerrainProtocol {
|
||||
case REQUESTUSETERRAINPALETTE: {
|
||||
attemptUseTerrainEditPalette(connectionHandler, message);
|
||||
} break;
|
||||
case REQUESTFLUIDDATA: {
|
||||
sendWorldFluidSubChunk(connectionHandler,
|
||||
message.getworldX(), message.getworldY(), message.getworldZ()
|
||||
);
|
||||
} break;
|
||||
//all ignored message types
|
||||
case RESPONSEMETADATA:
|
||||
case SPAWNPOSITION:
|
||||
case UPDATEVOXEL:
|
||||
case SENDCHUNKDATA:
|
||||
case SENDFLUIDDATA:
|
||||
//silently ignore
|
||||
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){
|
||||
//world metadata
|
||||
connectionHandler.addMessagetoOutgoingQueue(
|
||||
|
||||
@ -17,6 +17,7 @@ import electrosphere.renderer.model.Material;
|
||||
import electrosphere.renderer.model.Mesh;
|
||||
import electrosphere.renderer.model.Model;
|
||||
import electrosphere.renderer.shader.ShaderProgram;
|
||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||
|
||||
import static org.lwjgl.opengl.GL30.glBindVertexArray;
|
||||
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
|
||||
@ -559,7 +560,7 @@ public class FluidChunkModelGeneration {
|
||||
return new Vector3f(x,y,z);
|
||||
}
|
||||
|
||||
public static FluidChunkModelData generateFluidChunkData(float[][][] weightGrid, int[][][] typeGrid){
|
||||
public static FluidChunkModelData generateFluidChunkData(float[][][] weightGrid){
|
||||
|
||||
// 5 6
|
||||
// +-------------+ +-----5-------+ ^ Y
|
||||
@ -593,6 +594,9 @@ public class FluidChunkModelGeneration {
|
||||
for(int x = 0; x < weightGrid.length - 1; x++){
|
||||
for(int y = 0; y < weightGrid[0].length - 1; y++){
|
||||
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
|
||||
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),
|
||||
@ -665,6 +669,10 @@ public class FluidChunkModelGeneration {
|
||||
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
|
||||
FluidChunkModelData rVal = new FluidChunkModelData(vertsFlat, normalsFlat, elementsFlat, UVs);
|
||||
return rVal;
|
||||
@ -768,7 +776,13 @@ public class FluidChunkModelGeneration {
|
||||
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);
|
||||
@ -796,6 +810,7 @@ public class FluidChunkModelGeneration {
|
||||
m.setParent(rVal);
|
||||
|
||||
rVal.getMeshes().add(m);
|
||||
rVal.setBoundingSphere(m.getBoundingSphere());
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
@ -599,6 +599,9 @@ public class TerrainChunkModelGeneration {
|
||||
for(int x = 0; x < terrainGrid.length - 1; x++){
|
||||
for(int y = 0; y < terrainGrid[0].length - 1; y++){
|
||||
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
|
||||
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),
|
||||
|
||||
@ -21,6 +21,8 @@ import electrosphere.server.content.ServerContentManager;
|
||||
import electrosphere.server.datacell.interfaces.DataCellManager;
|
||||
import electrosphere.server.datacell.interfaces.VoxelCellManager;
|
||||
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.ServerTerrainChunk;
|
||||
|
||||
@ -43,6 +45,8 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
Realm parent;
|
||||
//Manager for terrain for this particular cell manager
|
||||
ServerTerrainManager serverTerrainManager;
|
||||
//manager for fluids for this particular cell manager
|
||||
ServerFluidManager serverFluidManager;
|
||||
//lock for terrain editing
|
||||
Semaphore terrainEditLock = new Semaphore(1);
|
||||
//manager for getting entities to fill in a cell
|
||||
@ -52,9 +56,15 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
* Constructor
|
||||
* @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.serverTerrainManager = serverTerrainManager;
|
||||
this.serverFluidManager = serverFluidManager;
|
||||
this.serverContentManager = serverContentManager;
|
||||
}
|
||||
|
||||
@ -344,6 +354,8 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
for(ServerDataCell cell : loadedCells){
|
||||
Globals.microSimulation.simulate(cell, parent.getHitboxManager());
|
||||
}
|
||||
//simulate fluid
|
||||
this.serverFluidManager.simulate();
|
||||
loadedCellsLock.release();
|
||||
updatePlayerPositions();
|
||||
}
|
||||
@ -357,6 +369,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
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.
|
||||
* 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerFluidChunk getFluidChunkAtPosition(Vector3i worldPosition) {
|
||||
return serverFluidManager.getChunk(worldPosition.x, worldPosition.y, worldPosition.z);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ public class RealmManager {
|
||||
//create realm
|
||||
Realm realm = new Realm(collisionEngine, new HitboxManager());
|
||||
//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();
|
||||
//init gridded manager
|
||||
griddedDataCellManager.init(serverWorldData);
|
||||
|
||||
@ -2,6 +2,7 @@ package electrosphere.server.datacell.interfaces;
|
||||
|
||||
import org.joml.Vector3i;
|
||||
|
||||
import electrosphere.server.fluid.manager.ServerFluidChunk;
|
||||
import electrosphere.server.terrain.manager.ServerTerrainChunk;
|
||||
|
||||
/**
|
||||
@ -40,5 +41,13 @@ public interface VoxelCellManager {
|
||||
* @param type The type to set the voxel to
|
||||
*/
|
||||
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