diff --git a/assets/Data/entity/items/tools.json b/assets/Data/entity/items/tools.json index 07ab4346..1c4b424d 100644 --- a/assets/Data/entity/items/tools.json +++ b/assets/Data/entity/items/tools.json @@ -92,6 +92,36 @@ "offsetZ" : 0 }, "iconPath" : "Textures/icons/itemIconItemGeneric.png" + }, + { + "id" : "waterSpawner", + "tokens" : [ + "GRAVITY", + "TARGETABLE" + ], + "equipData": { + "equipClass" : "tool" + }, + "graphicsTemplate": { + "model": { + "path" : "Models/basic/geometry/unitvector.glb" + } + }, + "clientSideSecondary": "SPAWN_WATER", + "collidable": { + "type" : "CUBE", + "dimension1" : 0.1, + "dimension2" : 0.1, + "dimension3" : 0.35, + "rotX": 0, + "rotY": 0, + "rotZ": 0, + "rotW": 1, + "offsetX" : 0, + "offsetY" : 0.05, + "offsetZ" : 0 + }, + "iconPath" : "Textures/icons/itemIconItemGeneric.png" } ], "files" : [ diff --git a/assets/Scripts/client/clienthooks.ts b/assets/Scripts/client/clienthooks.ts index 838925dc..f67fe1f2 100644 --- a/assets/Scripts/client/clienthooks.ts +++ b/assets/Scripts/client/clienthooks.ts @@ -34,5 +34,11 @@ export const clientHooks: Hook[] = [ callback: (engine: Engine) => { engine.classes.levelEditorUtils.static.inspectEntity() } + }, + { + signal: "SPAWN_WATER", + callback: (engine: Engine) => { + engine.classes.voxelUtils.static.spawnWater() + } } ] \ No newline at end of file diff --git a/assets/Scripts/types/host/client/client-voxel-utils.ts b/assets/Scripts/types/host/client/client-voxel-utils.ts index d6d9e03c..2c0d871d 100644 --- a/assets/Scripts/types/host/client/client-voxel-utils.ts +++ b/assets/Scripts/types/host/client/client-voxel-utils.ts @@ -8,4 +8,9 @@ export interface ClientVoxelUtils { */ readonly applyEdit: () => void + /** + * Spawns water at the player's cursor + */ + readonly spawnWater: () => void + } \ No newline at end of file diff --git a/assets/Shaders/entities/fluid2/fluid2.fs b/assets/Shaders/entities/fluid2/fluid2.fs index db6cbe98..5d3597a8 100644 --- a/assets/Shaders/entities/fluid2/fluid2.fs +++ b/assets/Shaders/entities/fluid2/fluid2.fs @@ -1,36 +1,8 @@ -#version 330 core - -#define NR_POINT_LIGHTS 10 - -out vec4 FragColor; +#version 450 core +#extension GL_ARB_shading_language_include : require +#include "../../lib/lights.fs" -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; @@ -47,26 +19,12 @@ 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; +out vec4 FragColor; // 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(){ @@ -80,14 +38,10 @@ void main(){ vec3 textureColor = vec3(0.6, 0.92, 0.92);//getColor(texPlane1, texPlane2, texPlane3, norm, material); //shadow - float shadow = ShadowCalculation(FragPosLightSpace, normalize(-dLDirection), norm); + float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), 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, 0.2); @@ -104,105 +58,4 @@ vec3 getColor(vec2 texPlane1, vec2 texPlane2, vec2 texPlane3, vec3 normal, Mater 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; } \ No newline at end of file diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index ecce7d89..74cc2691 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1186,6 +1186,9 @@ Fix AABB calculation from assimp-loaded models Fix singleplayer launching at all Store characters in database Spawn characters from database +Fluid spawning item +Fix fluid shader +Re-enable fluid simulation # TODO diff --git a/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java b/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java index 7754b4b4..c4bd2db3 100644 --- a/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java +++ b/src/main/java/electrosphere/client/script/ScriptClientVoxelUtils.java @@ -2,12 +2,14 @@ package electrosphere.client.script; import org.graalvm.polyglot.HostAccess.Export; import org.joml.Vector3d; +import org.joml.Vector3i; import electrosphere.client.entity.camera.CameraEntityUtils; import electrosphere.client.terrain.editing.TerrainEditing; import electrosphere.collision.CollisionEngine; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.server.terrain.manager.ServerTerrainChunk; /** * Utilities for interacting with voxels from the client @@ -39,4 +41,36 @@ public class ScriptClientVoxelUtils { } } + /** + * Applies the current voxel palette where the player's cursor is looking + */ + @Export + public static void spawnWater(){ + CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine(); + Entity camera = Globals.playerCamera; + if( + collisionEngine != null && + camera != null && + Globals.realmManager != null && + Globals.realmManager.first() != null && + Globals.realmManager.first().getServerWorldData() != null && + Globals.realmManager.first().getServerWorldData().getServerFluidManager() != null + ){ + Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera)); + Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera)); + Vector3d cursorPos = collisionEngine.rayCastPosition(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1.0), CollisionEngine.DEFAULT_INTERACT_DISTANCE); + Vector3i worldPos = new Vector3i( + (int)(cursorPos.x / ServerTerrainChunk.CHUNK_DIMENSION), + (int)(cursorPos.y / ServerTerrainChunk.CHUNK_DIMENSION), + (int)(cursorPos.z / ServerTerrainChunk.CHUNK_DIMENSION) + ); + Vector3i voxelPos = new Vector3i( + (int)(cursorPos.x % ServerTerrainChunk.CHUNK_DIMENSION), + (int)(cursorPos.y % ServerTerrainChunk.CHUNK_DIMENSION), + (int)(cursorPos.z % ServerTerrainChunk.CHUNK_DIMENSION) + ); + Globals.realmManager.first().getServerWorldData().getServerFluidManager().deformFluidAtLocationToValue(worldPos, voxelPos, 1.0f, 0); + } + } + } diff --git a/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java index 46979535..6f2c9346 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java +++ b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java @@ -166,6 +166,7 @@ public class LoadingUtils { template.getCreatureToolbarData().setSlotItem("0", new ToolbarItem(71, "terrainTool")); template.getCreatureToolbarData().setSlotItem("1", new ToolbarItem(72, "spawningPalette")); template.getCreatureToolbarData().setSlotItem("2", new ToolbarItem(73, "entityinspector")); + template.getCreatureToolbarData().setSlotItem("3", new ToolbarItem(74, "waterSpawner")); //set player character template serverPlayerConnection.setCreatureTemplate(template); Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage(CharacterProtocol.SPAWN_EXISTING_TEMPLATE + "")); diff --git a/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java b/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java index b7ea819e..df54ee94 100644 --- a/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java @@ -166,6 +166,7 @@ public class CharacterProtocol implements ServerProtocolTemplate(); this.seed = seed; this.chunkGenerator = chunkGenerator; + this.serverFluidSimulator = new FluidCellularAutomataSimulator(); } ServerFluidManager(){ @@ -85,14 +87,6 @@ public class ServerFluidManager { * 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(); } /** @@ -265,6 +259,8 @@ public class ServerFluidManager { // ServerFluidChunk chunk = chunkCache.get(key); // chunk.addModification(modification); // } + ServerFluidChunk fluidChunk = this.getChunk(worldPos.x, worldPos.y, worldPos.z); + fluidChunk.setWeight(voxelPos.x, voxelPos.y, voxelPos.z, weight); } /** @@ -273,13 +269,13 @@ public class ServerFluidManager { public boolean simulate(int worldX, int worldY, int worldZ){ boolean rVal = false; Globals.profiler.beginAggregateCpuSample("ServerFluidManager.simulate"); - // if(simulate){ - // ServerFluidChunk fluidChunk = this.getChunk(worldX, worldY, worldZ); - // ServerTerrainChunk terrainChunk = this.serverTerrainManager.getChunk(worldX, worldY, worldZ); - // if(fluidChunk != null && terrainChunk != null && this.serverFluidSimulator != null){ - // rVal = this.serverFluidSimulator.simulate(fluidChunk,terrainChunk,worldX,worldY,worldZ); - // } - // } + if(simulate){ + ServerFluidChunk fluidChunk = this.getChunk(worldX, worldY, worldZ); + ServerTerrainChunk terrainChunk = this.serverTerrainManager.getChunk(worldX, worldY, worldZ); + if(fluidChunk != null && terrainChunk != null && this.serverFluidSimulator != null){ + rVal = this.serverFluidSimulator.simulate(fluidChunk,terrainChunk,worldX,worldY,worldZ); + } + } Globals.profiler.endCpuSample(); return rVal; }