diff --git a/assets/Data/entity/items.json b/assets/Data/entity/items.json
index 9f8e7d86..7df0503a 100644
--- a/assets/Data/entity/items.json
+++ b/assets/Data/entity/items.json
@@ -125,6 +125,12 @@
"path" : "Models/items/weapons/katana1alt.glb"
}
},
+ "boneGroups" : [
+ {
+ "id" : "torso",
+ "boneNamesThirdPerson" : []
+ }
+ ],
"collidable": {
"type" : "CUBE",
"dimension1" : 0.04,
diff --git a/assets/Scripts/server/chunk/generators/testgen.ts b/assets/Scripts/server/chunk/generators/testgen.ts
index 89bbac55..f489323a 100644
--- a/assets/Scripts/server/chunk/generators/testgen.ts
+++ b/assets/Scripts/server/chunk/generators/testgen.ts
@@ -102,16 +102,13 @@ export const TestGen: ChunkGenerator = {
engine: Engine
): VoxelFunction => {
const rVal = (
+ voxel: GeneratedVoxel,
worldX: number, worldY: number, worldZ: number,
chunkX: number, chunkY: number, chunkZ: number,
stride: number,
surfaceHeight: number,
surfaceBiome: BiomeData
- ): GeneratedVoxel => {
- let rVal: GeneratedVoxel = {
- type: 0,
- weight: -1,
- }
+ ): void => {
const realX = voxelToReal(chunkX,worldX)
const realY = voxelToReal(chunkY,worldY)
@@ -122,8 +119,8 @@ export const TestGen: ChunkGenerator = {
const surfacePercent = (surfaceHeight - realY) / strideMultiplier
if(heightDiff < -strideMultiplier){
- return getSubsurfaceVoxel(
- rVal,
+ getSubsurfaceVoxel(
+ voxel,
worldX, worldY, worldZ,
chunkX, chunkY, chunkZ,
realX, realY, realZ,
@@ -132,8 +129,8 @@ export const TestGen: ChunkGenerator = {
surfaceBiome
);
} else if(heightDiff > 0) {
- return getOverSurfaceVoxel(
- rVal,
+ getOverSurfaceVoxel(
+ voxel,
worldX, worldY, worldZ,
chunkX, chunkY, chunkZ,
realX, realY, realZ,-
@@ -142,8 +139,8 @@ export const TestGen: ChunkGenerator = {
surfaceBiome
);
} else {
- return getSurfaceVoxel(
- rVal,
+ getSurfaceVoxel(
+ voxel,
worldX, worldY, worldZ,
chunkX, chunkY, chunkZ,
realX, realY, realZ,
diff --git a/assets/Scripts/types/host/server/chunk/chunkgenerator.ts b/assets/Scripts/types/host/server/chunk/chunkgenerator.ts
index 81753229..8d807db7 100644
--- a/assets/Scripts/types/host/server/chunk/chunkgenerator.ts
+++ b/assets/Scripts/types/host/server/chunk/chunkgenerator.ts
@@ -25,6 +25,7 @@ export interface GeneratedVoxel {
/**
* Gets a voxel for a given position
+* @param voxel The voxel to fill with values
* @param worldX The world x coordinate of the chunk
* @param worldY The world y coordinate of the chunk
* @param worldZ The world z coordinate of the chunk
@@ -38,12 +39,13 @@ export interface GeneratedVoxel {
* @returns The voxel at the provided position
*/
export type VoxelFunction = (
+ voxel: GeneratedVoxel,
worldX: number, worldY: number, worldZ: number,
chunkX: number, chunkY: number, chunkZ: number,
stride: number,
surfaceHeight: number,
surfaceBiome: BiomeData
-) => GeneratedVoxel;
+) => void;
diff --git a/assets/Shaders/entities/terrain2/terrain2.fs b/assets/Shaders/entities/terrain2/terrain2.fs
index fc499180..1a6af4c8 100644
--- a/assets/Shaders/entities/terrain2/terrain2.fs
+++ b/assets/Shaders/entities/terrain2/terrain2.fs
@@ -130,7 +130,7 @@ void main(){
vec3 textureColor = getColor(texPlane1, texPlane2, texPlane3, norm, samplerIndexVec, samplerRatioVec, material);
//shadow
- float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), norm);
+ float shadow = ShadowCalculation(FragPosLightSpace, normalize(-directLight.direction), -norm);
//
//point light calculations
@@ -350,5 +350,5 @@ float ShadowCalculation(vec4 fragPosLightSpace, vec3 lightDir, vec3 normal){
// shadow = currentDepth;
- return shadow;
+ return clamp(1.0 - shadow, 0.0, 0.7);
}
\ No newline at end of file
diff --git a/buildNumber.properties b/buildNumber.properties
index 38e2d8f5..f5e3fc8f 100644
--- a/buildNumber.properties
+++ b/buildNumber.properties
@@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file
-#Sun Nov 10 17:05:45 EST 2024
-buildNumber=378
+#Wed Nov 13 13:33:32 EST 2024
+buildNumber=381
diff --git a/docs/src/architecture/generation/biomegenerationproblems.md b/docs/src/architecture/generation/biomegenerationproblems.md
index 4428118f..f58982a5 100644
--- a/docs/src/architecture/generation/biomegenerationproblems.md
+++ b/docs/src/architecture/generation/biomegenerationproblems.md
@@ -10,4 +10,13 @@ Different cases to consider when working on a biome generation system
- Superstructure biomes (World tree, massive mountains, etc)
- Oceans
- Lakes
- - Rivers
\ No newline at end of file
+ - Rivers
+ - Large scale overhangs
+
+
+Operations we might want to do
+ - Placing things on the surface
+ - Solve navgation at the macro scale
+
+
+
diff --git a/docs/src/architecture/generation/terraingenerationprocess.md b/docs/src/architecture/generation/terraingenerationprocess.md
index fc7551dc..f4e7ce7c 100644
--- a/docs/src/architecture/generation/terraingenerationprocess.md
+++ b/docs/src/architecture/generation/terraingenerationprocess.md
@@ -60,3 +60,14 @@ store fire pixels as "good for fire civilization"
when a pixel changes biome, must evict it from all these structures and recalculate which ones it should be within (except maybe zone)
+
+
+
+
+
+Solve for the heightmap at a given x-z for the surface
+Then, have "cells" placed above the surface based on the base height offset of the biome
+These cells can be populated with larger structures
+
+
+
diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md
index 29c0374e..9237f530 100644
--- a/docs/src/progress/renderertodo.md
+++ b/docs/src/progress/renderertodo.md
@@ -1001,6 +1001,18 @@ Passing chunk data between nodes
Fix homogenous value propagating from chunk gen to client cache
Fix homogenous value joining on client
+(11/12/2024)
+Work to optimize javascript chunk generators
+Solve curve SDF
+
+(11/13/2024)
+Fix shadows on terrain
+Work on an anime-style mountain generator
+Work on making chunk reloading less obvious
+Fix default chunk generator
+Fix unit test
+Fix missing data on katana item
+
# TODO
diff --git a/net/character.json b/net/character.json
index 8c2262eb..96c9395c 100644
--- a/net/character.json
+++ b/net/character.json
@@ -51,6 +51,11 @@
"data" : [
"data"
]
+ },
+ {
+ "messageName" : "EditorSwap",
+ "description" : "Swaps between the editor entity and the non-editor entity",
+ "data" : []
}
]
}
diff --git a/pom.xml b/pom.xml
index e0081515..ff55397a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -305,7 +305,7 @@
io.github.studiorailgun
MathUtils
- 1.1.0
+ 1.3.0
diff --git a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java
index be764f03..6187e5c7 100644
--- a/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java
+++ b/src/main/java/electrosphere/client/terrain/cells/ClientDrawCellManager.java
@@ -184,31 +184,6 @@ public class ClientDrawCellManager {
if(!updatedLastFrame && !this.initialized){
this.initialized = true;
}
- // if(!updatedLastFrame){
- // Globals.profiler.beginCpuSample("ClientDrawCellManager.update - half res cells");
- // updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerWorldPos, evaluationMap, HALF_RES_LOD, distCache);
- // Globals.profiler.endCpuSample();
- // }
- // if(!updatedLastFrame){
- // Globals.profiler.beginCpuSample("ClientDrawCellManager.update - half res cells");
- // updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerWorldPos, evaluationMap, QUARTER_RES_LOD, distCache);
- // Globals.profiler.endCpuSample();
- // }
- // if(!updatedLastFrame){
- // Globals.profiler.beginCpuSample("ClientDrawCellManager.update - quarter res cells");
- // updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerWorldPos, evaluationMap, EIGHTH_RES_LOD, distCache);
- // Globals.profiler.endCpuSample();
- // }
- // if(!updatedLastFrame){
- // Globals.profiler.beginCpuSample("ClientDrawCellManager.update - eighth res cells");
- // updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerWorldPos, evaluationMap, SIXTEENTH_RES_LOD, distCache);
- // Globals.profiler.endCpuSample();
- // }
- // if(!updatedLastFrame){
- // Globals.profiler.beginCpuSample("ClientDrawCellManager.update - all res cells");
- // updatedLastFrame = this.recursivelyUpdateCells(rootNode, playerPos, evaluationMap, ALL_RES_LOD);
- // Globals.profiler.endCpuSample();
- // }
}
Globals.profiler.endCpuSample();
}
diff --git a/src/main/java/electrosphere/client/terrain/cells/DrawCell.java b/src/main/java/electrosphere/client/terrain/cells/DrawCell.java
index 15ec72fb..d248dc21 100644
--- a/src/main/java/electrosphere/client/terrain/cells/DrawCell.java
+++ b/src/main/java/electrosphere/client/terrain/cells/DrawCell.java
@@ -11,6 +11,7 @@ import electrosphere.collision.CollisionEngine;
import electrosphere.engine.Globals;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
+import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.types.terrain.TerrainChunk;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
@@ -23,6 +24,11 @@ import electrosphere.util.math.GeomUtils;
*/
public class DrawCell {
+ /**
+ * Number of frames to wait before destroying the chunk entity
+ */
+ public static final int FRAMES_TO_WAIT_BEFORE_DESTRUCTION = 15;
+
/**
* Enum for the different faces of a draw cell -- used when filling in data for higher LOD faces
*/
@@ -188,9 +194,19 @@ public class DrawCell {
*/
public void destroy(){
if(modelEntity != null){
- CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
- collisionEngine.destroyPhysics(modelEntity);
- ClientEntityUtils.destroyEntity(modelEntity);
+ Globals.clientScene.registerBehaviorTree(new BehaviorTree(){
+ int framesSimulated = 0;
+ public void simulate(float deltaTime) {
+ if(framesSimulated < FRAMES_TO_WAIT_BEFORE_DESTRUCTION){
+ framesSimulated++;
+ } else {
+ CollisionEngine collisionEngine = Globals.clientSceneWrapper.getCollisionEngine();
+ collisionEngine.destroyPhysics(modelEntity);
+ ClientEntityUtils.destroyEntity(modelEntity);
+ Globals.clientScene.deregisterBehaviorTree(this);
+ }
+ }
+ });
}
}
diff --git a/src/main/java/electrosphere/entity/ClientEntityUtils.java b/src/main/java/electrosphere/entity/ClientEntityUtils.java
index 54fc1c38..f1ebf60f 100644
--- a/src/main/java/electrosphere/entity/ClientEntityUtils.java
+++ b/src/main/java/electrosphere/entity/ClientEntityUtils.java
@@ -57,6 +57,9 @@ public class ClientEntityUtils {
if(Globals.clientSceneWrapper != null){
Globals.clientSceneWrapper.getScene().deregisterEntity(entity);
Globals.clientSceneWrapper.deregisterTranslationMapping(entity);
+ if(Globals.clientSceneWrapper.getCollisionEngine() != null){
+ Globals.clientSceneWrapper.getCollisionEngine().destroyPhysics(entity);
+ }
}
if(Globals.clientScene != null){
Globals.clientScene.deregisterEntity(entity);
diff --git a/src/main/java/electrosphere/entity/state/physicssync/ServerPhysicsSyncTree.java b/src/main/java/electrosphere/entity/state/physicssync/ServerPhysicsSyncTree.java
index ccbfbde0..b2f5e48b 100644
--- a/src/main/java/electrosphere/entity/state/physicssync/ServerPhysicsSyncTree.java
+++ b/src/main/java/electrosphere/entity/state/physicssync/ServerPhysicsSyncTree.java
@@ -11,7 +11,6 @@ import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree;
-import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
@@ -46,7 +45,6 @@ public class ServerPhysicsSyncTree implements BehaviorTree {
Quaterniond rotation = EntityUtils.getRotation(parent);
DBody body = PhysicsEntityUtils.getDBody(parent);
if(body == null){
- LoggerInterface.loggerEngine.ERROR(new IllegalStateException("Running physics sync tree on entity that does not have a physics body!"));
} else {
//velocities
Vector3d linearVel = PhysicsUtils.odeVecToJomlVec(body.getLinearVel());
diff --git a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java
index e40b0520..8839a2e2 100644
--- a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java
+++ b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java
@@ -63,7 +63,7 @@ public class TerrainChunk {
}
rVal.putData(EntityDataStrings.HAS_UNIQUE_MODEL, true);
} else {
- LoggerInterface.loggerEngine.WARNING("Finished generating terrain polygons; however, entity has already been deleted.");
+ LoggerInterface.loggerEngine.DEBUG("Finished generating terrain polygons; however, entity has already been deleted.");
}
} catch (Error e){
LoggerInterface.loggerEngine.ERROR(e);
diff --git a/src/main/java/electrosphere/renderer/actor/Actor.java b/src/main/java/electrosphere/renderer/actor/Actor.java
index 87140163..93ff80e7 100644
--- a/src/main/java/electrosphere/renderer/actor/Actor.java
+++ b/src/main/java/electrosphere/renderer/actor/Actor.java
@@ -251,7 +251,11 @@ public class Actor {
}
}
} else if(this.boneGroups == null){
- LoggerInterface.loggerRenderer.WARNING("Trying to play animation on pose actor that uses bone groups, but the actor's bone group isn't defined!");
+ LoggerInterface.loggerRenderer.WARNING(
+ "Trying to play animation on Actor that uses bone groups, but the Actor's bone group isn't defined!\n" +
+ "Model path: " + modelPath + "\n" +
+ "Animation name: " + animationName + "\n"
+ );
}
diff --git a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java
index faab8a98..6653d49a 100644
--- a/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java
+++ b/src/main/java/electrosphere/renderer/pipelines/ShadowMapPipeline.java
@@ -31,17 +31,22 @@ public class ShadowMapPipeline implements RenderPipeline {
/**
* The eye of the camera that is used to render the shadow map
*/
- Vector3d cameraEye = new Vector3d(-1,10,-5.5);
+ Vector3d cameraEye = new Vector3d(-1,20,-5.5);
/**
* The near plane distance
*/
- float nearPlane = 0.1f;
+ float nearPlane = 1f;
/**
* The far plane
*/
- float farPlane = 25f;
+ float farPlane = 40f;
+
+ /**
+ * Sides of the orthagonal box
+ */
+ float sideLength = 50f;
/**
* Sets whether the far plane should update based on camera location or not
@@ -68,9 +73,10 @@ public class ShadowMapPipeline implements RenderPipeline {
float eyeX = (float)cameraEye.x;
float eyeY = (float)cameraEye.y;
float eyeZ = (float)cameraEye.z;
- float eyeDist = (float)cameraEye.length();
+ // float eyeDist = (float)cameraEye.length();
// float farPlane = eyeDist + 10.0f;
- float sidesMagnitude = (float)Math.sqrt(eyeDist);
+ // float sidesMagnitude = (float)Math.sqrt(eyeDist);
+ float sidesMagnitude = sideLength;
//set matrices for light render
Matrix4f lightProjection = new Matrix4f().setOrtho(-sidesMagnitude, sidesMagnitude, -sidesMagnitude, sidesMagnitude, nearPlane, farPlane);//glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);
Matrix4f lightView = new Matrix4f().setLookAt(
diff --git a/src/main/java/electrosphere/server/content/ServerContentGenerator.java b/src/main/java/electrosphere/server/content/ServerContentGenerator.java
index df7bdbcf..934d8bff 100644
--- a/src/main/java/electrosphere/server/content/ServerContentGenerator.java
+++ b/src/main/java/electrosphere/server/content/ServerContentGenerator.java
@@ -48,11 +48,11 @@ public class ServerContentGenerator {
);
}
- //setup
- Random random = new Random(randomizer);
+ // //setup
+ // Random random = new Random(randomizer);
- //generate foliage
+ // //generate foliage
// BiomeData biome = null;
// if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null && realm.getServerWorldData().getServerTerrainManager().getModel() != null){
// biome = realm.getServerWorldData().getServerTerrainManager().getModel().getSurfaceBiome(worldPos.x, worldPos.z);
diff --git a/src/main/java/electrosphere/server/poseactor/PoseActor.java b/src/main/java/electrosphere/server/poseactor/PoseActor.java
index 24a8c9ae..fc85a8b0 100644
--- a/src/main/java/electrosphere/server/poseactor/PoseActor.java
+++ b/src/main/java/electrosphere/server/poseactor/PoseActor.java
@@ -224,7 +224,11 @@ public class PoseActor {
}
}
} else if(this.boneGroups == null){
- LoggerInterface.loggerRenderer.WARNING("Trying to play animation on pose actor that uses bone groups, but the actor's bone group isn't defined!");
+ LoggerInterface.loggerRenderer.WARNING(
+ "Trying to play animation on PoseActor that uses bone groups, but the PoseActor's bone group isn't defined!\n" +
+ "Model path: " + modelPath + "\n" +
+ "Animation name: " + animationName + "\n"
+ );
}
diff --git a/src/main/java/electrosphere/server/terrain/generation/DefaultChunkGenerator.java b/src/main/java/electrosphere/server/terrain/generation/DefaultChunkGenerator.java
index 84f1abbd..fc821acf 100644
--- a/src/main/java/electrosphere/server/terrain/generation/DefaultChunkGenerator.java
+++ b/src/main/java/electrosphere/server/terrain/generation/DefaultChunkGenerator.java
@@ -26,19 +26,19 @@ public class DefaultChunkGenerator implements ChunkGenerator {
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ, int stride) {
//Each chunk also needs custody of the next chunk's first values so that they can perfectly overlap.
//Hence, width should actually be chunk dimension + 1
- float[][][] weights = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
- int[][][] values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
- for(int inc = 0; inc < ServerTerrainChunk.CHUNK_DIMENSION; inc++){
- for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DIMENSION; weightX++){
- for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DIMENSION; weightZ++){
+ float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
+ int[][][] values = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
+ for(int inc = 0; inc < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; inc++){
+ for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){
+ for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){
weights[weightX][inc][weightZ] = -1;
values[weightX][inc][weightZ] = 0;
}
}
}
if(worldY < 1){
- for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DIMENSION; weightX++){
- for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DIMENSION; weightZ++){
+ for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){
+ for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){
weights[weightX][0][weightZ] = 0.1f;
values[weightX][0][weightZ] = baseVoxelId;
}
diff --git a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java
index a781391f..76834c39 100644
--- a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java
+++ b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java
@@ -5,7 +5,7 @@ import java.util.Map;
import electrosphere.client.terrain.cache.ChunkData;
-// import org.graalvm.polyglot.Value;
+import org.graalvm.polyglot.Value;
import electrosphere.engine.Globals;
import electrosphere.game.data.biome.BiomeData;
@@ -17,6 +17,10 @@ import electrosphere.server.terrain.generation.heightmap.HillsGen;
import electrosphere.server.terrain.generation.heightmap.PlainsGen;
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
+import electrosphere.server.terrain.generation.interfaces.GenerationContext;
+import electrosphere.server.terrain.generation.voxelphase.AnimeMountainsGen;
+import electrosphere.server.terrain.generation.voxelphase.HillsVoxelGen;
+import electrosphere.server.terrain.generation.voxelphase.VoxelGenerator;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.models.TerrainModel;
@@ -61,9 +65,14 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
ServerWorldData serverWorldData;
/**
- * Map of generator tag to the generator
+ * The map of generator tag to the heightmap generator
*/
- Map tagGeneratorMap = new HashMap();
+ Map tagHeightmapMap = new HashMap();
+
+ /**
+ * The map of generator tag to voxel generator
+ */
+ Map tagVoxelMap = new HashMap();
/**
* Tracks whether to use javascript generation or not
@@ -75,9 +84,11 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
*/
public TestGenerationChunkGenerator(ServerWorldData serverWorldData, boolean useJavascript){
this.serverWorldData = serverWorldData;
- registerGenerator(new EmptySkyGen());
- registerGenerator(new HillsGen());
- registerGenerator(new PlainsGen());
+ registerHeightmapGenerator(new EmptySkyGen());
+ registerHeightmapGenerator(new HillsGen());
+ registerHeightmapGenerator(new PlainsGen());
+ registerVoxelGenerator(new HillsVoxelGen());
+ registerVoxelGenerator(new AnimeMountainsGen());
this.useJavascript = useJavascript;
}
@@ -85,27 +96,31 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
* Registers a heightmap generator
* @param generator The heightmap generator
*/
- private void registerGenerator(HeightmapGenerator generator){
- tagGeneratorMap.put(generator.getTag(),generator);
+ private void registerHeightmapGenerator(HeightmapGenerator generator){
+ tagHeightmapMap.put(generator.getTag(),generator);
+ }
+
+ /**
+ * Registers a voxel generator
+ * @param generator The voxel generator
+ */
+ private void registerVoxelGenerator(VoxelGenerator generator){
+ tagVoxelMap.put(generator.getTag(),generator);
}
@Override
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ, int stride) {
Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator.generateChunk");
- ServerTerrainChunk rVal = null;
+ ServerTerrainChunk rVal = new ServerTerrainChunk(worldX, worldY, worldZ);
float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];;
int[][][] values = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
- int firstType = -2;
- boolean homogenous = true;
try {
- //actual generation algo
-
//biome of the current chunk
BiomeData surfaceBiome = this.terrainModel.getSurfaceBiome(worldX, worldZ);
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
- HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
+ HeightmapGenerator heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag());
if(heightmapGen == null){
throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
}
@@ -129,39 +144,58 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
}
}
+ VoxelGenerator voxelGenerator = this.tagVoxelMap.get("hills");
+
if(this.useJavascript){
- // Globals.scriptEngine.executeSynchronously(() -> {
- // Value getVoxelFunc = Globals.scriptEngine.invokeEngineMember("chunkGeneratorManager", "getVoxelFunction", SCRIPT_GEN_TEST_TAG);
- // for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
- // Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
- // for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
- // for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
- // int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
- // int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
- // int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
- // int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
- // int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
- // int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
- // Value result = getVoxelFunc.execute(
- // finalWorldX, finalWorldY, finalWorldZ,
- // finalChunkX, finalChunkY, finalChunkZ,
- // stride,
- // heightfield[x][z],
- // surfaceBiome
- // );
- // if(result != null){
- // weights[x][y][z] = result.getMember("weight").asFloat();
- // values[x][y][z] = result.getMember("type").asInt();
- // }
- // }
- // }
- // Globals.profiler.endCpuSample();
- // }
- // });
+ Globals.scriptEngine.executeSynchronously(() -> {
+ int firstType = -2;
+ boolean homogenous = true;
+ GeneratedVoxel voxel = new GeneratedVoxel();
+ Value getVoxelFunc = Globals.scriptEngine.invokeEngineMember("chunkGeneratorManager", "getVoxelFunction", SCRIPT_GEN_TEST_TAG);
+ for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){
+ Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
+ for(int y = 0; y < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; y++){
+ for(int z = 0; z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; z++){
+ int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
+ int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
+ int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
+ int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
+ int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
+ int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
+ getVoxelFunc.execute(
+ voxel,
+ finalWorldX, finalWorldY, finalWorldZ,
+ finalChunkX, finalChunkY, finalChunkZ,
+ stride,
+ heightfield[x][z],
+ surfaceBiome
+ );
+ weights[x][y][z] = voxel.weight;
+ values[x][y][z] = voxel.type;
+ if(firstType == -2){
+ firstType = values[x][y][z];
+ } else if(homogenous && firstType != values[x][y][z]){
+ homogenous = false;
+ }
+ }
+ }
+ Globals.profiler.endCpuSample();
+ }
+ if(homogenous){
+ rVal.setHomogenousValue(firstType);
+ } else {
+ rVal.setHomogenousValue(ChunkData.NOT_HOMOGENOUS);
+ }
+ rVal.setWeights(weights);
+ rVal.setValues(values);
+ });
} else {
+ int firstType = -2;
+ boolean homogenous = true;
GeneratedVoxel voxel = new GeneratedVoxel();
+ GenerationContext generationContext = new GenerationContext();
+ generationContext.setServerWorldData(serverWorldData);
for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){
- Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator - Generate slice");
for(int y = 0; y < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; z++){
int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION);
@@ -170,13 +204,14 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
int finalChunkY = (y * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION;
- this.getVoxel(
+ voxelGenerator.getVoxel(
voxel,
finalWorldX, finalWorldY, finalWorldZ,
finalChunkX, finalChunkY, finalChunkZ,
stride,
heightfield[x][z],
- surfaceBiome
+ surfaceBiome,
+ generationContext
);
if(voxel != null){
weights[x][y][z] = voxel.weight;
@@ -189,13 +224,18 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
}
}
}
- Globals.profiler.endCpuSample();
}
+ if(homogenous){
+ rVal.setHomogenousValue(firstType);
+ } else {
+ rVal.setHomogenousValue(ChunkData.NOT_HOMOGENOUS);
+ }
+ rVal.setWeights(weights);
+ rVal.setValues(values);
}
} catch(Exception ex){
ex.printStackTrace();
}
- rVal = new ServerTerrainChunk(worldX, worldY, worldZ, homogenous ? firstType : ChunkData.NOT_HOMOGENOUS, weights, values);
Globals.profiler.endCpuSample();
return rVal;
}
@@ -205,7 +245,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
BiomeData surfaceBiome = this.terrainModel.getSurfaceBiome(worldX, worldZ);
BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
- HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
+ HeightmapGenerator heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag());
if(heightmapGen == null){
throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
}
@@ -222,140 +262,4 @@ public class TestGenerationChunkGenerator implements ChunkGenerator {
this.terrainModel = model;
}
- /**
- * Gets the value for a chunk
- * @param voxel The voxel to fill
- * @param worldX The world x pos
- * @param worldY The world y pos
- * @param worldZ The world z pos
- * @param chunkX The chunk x pos
- * @param chunkY The chunk y pos
- * @param chunkZ The chunk z pos
- * @param stride The stride of the data
- * @param surfaceHeight The height of the surface at x,z
- * @param surfaceBiome The surface biome of the chunk
- */
- private void getVoxel(
- GeneratedVoxel voxel,
- int worldX, int worldY, int worldZ,
- int chunkX, int chunkY, int chunkZ,
- int stride,
- float surfaceHeight,
- BiomeData surfaceBiome
- ){
- Globals.profiler.beginAggregateCpuSample("TestGenerationChunkGenerator.getChunkValue");
- BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams();
- HeightmapGenerator heightmapGen = this.tagGeneratorMap.get(surfaceParams.getSurfaceGenTag());
- if(heightmapGen == null){
- throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag());
- }
-
- double realX = this.serverWorldData.convertVoxelToRealSpace(chunkX,worldX);
- double realY = this.serverWorldData.convertVoxelToRealSpace(chunkY,worldY);
- double realZ = this.serverWorldData.convertVoxelToRealSpace(chunkZ,worldZ);
-
- double strideMultiplier = Math.pow(2,stride);
- double heightDiff = realY - surfaceHeight;
- double surfacePercent = TestGenerationChunkGenerator.getSurfaceWeight(surfaceHeight,realY,strideMultiplier);
- Globals.profiler.endCpuSample();
- if(heightDiff < -strideMultiplier * SURFACE_VOXEL_WIDTH){
- getSubsurfaceVoxel(
- voxel,
- worldX, worldY, worldZ,
- chunkX, chunkY, chunkZ,
- realX, realY, realZ,
- surfacePercent,
- surfaceHeight,
- surfaceBiome
- );
- } else if(heightDiff > 0) {
- getOverSurfaceVoxel(
- voxel,
- worldX, worldY, worldZ,
- chunkX, chunkY, chunkZ,
- realX, realY, realZ,-
- surfacePercent,
- surfaceHeight,
- surfaceBiome
- );
- } else {
- getSurfaceVoxel(
- voxel,
- worldX, worldY, worldZ,
- chunkX, chunkY, chunkZ,
- realX, realY, realZ,
- surfacePercent,
- surfaceHeight,
- surfaceBiome
- );
- }
- }
-
- /**
- * Gets the voxel on the surface
- * @return The voxel
- */
- private void getSurfaceVoxel(
- GeneratedVoxel voxel,
- int worldX, int worldY, int worldZ,
- int chunkX, int chunkY, int chunkZ,
- double realX, double realY, double realZ,
- double surfacePercent,
- float surfaceHeight,
- BiomeData surfaceBiome
- ){
- voxel.weight = (float)surfacePercent * 2 - 1;
- voxel.type = 2;
- }
-
- /**
- * Gets the voxel below the surface
- * @return The voxel
- */
- private void getSubsurfaceVoxel(
- GeneratedVoxel voxel,
- int worldX, int worldY, int worldZ,
- int chunkX, int chunkY, int chunkZ,
- double realX, double realY, double realZ,
- double surfacePercent,
- float surfaceHeight,
- BiomeData surfaceBiome
- ){
- if(realY < surfaceHeight - 5){
- voxel.weight = 1;
- voxel.type = 6;
- } else {
- voxel.weight = 1;
- voxel.type = 1;
- }
- }
-
- /**
- * Gets the voxel above the service
- * @return The voxel
- */
- private void getOverSurfaceVoxel(
- GeneratedVoxel voxel,
- int worldX, int worldY, int worldZ,
- int chunkX, int chunkY, int chunkZ,
- double realX, double realY, double realZ,
- double surfacePercent,
- float surfaceHeight,
- BiomeData surfaceBiome
- ){
- voxel.weight = -1;
- voxel.type = 0;
- }
-
- /**
- * Calculates the weight of a voxel on the surface based on the surface height, the position of the voxel, and the stride multiplier
- * @param surfaceHeight The surface height
- * @param realPosY The position of the voxel
- * @param strideMultiplier The stride multiplier
- * @return The weight of the voxel
- */
- protected static double getSurfaceWeight(double surfaceHeight, double realPosY, double strideMultiplier){
- return ((surfaceHeight - realPosY) / strideMultiplier);
- }
-
}
diff --git a/src/main/java/electrosphere/server/terrain/generation/heightmap/HillsGen.java b/src/main/java/electrosphere/server/terrain/generation/heightmap/HillsGen.java
index 3cb97bf8..941676e5 100644
--- a/src/main/java/electrosphere/server/terrain/generation/heightmap/HillsGen.java
+++ b/src/main/java/electrosphere/server/terrain/generation/heightmap/HillsGen.java
@@ -52,7 +52,7 @@ public class HillsGen implements HeightmapGenerator {
Globals.profiler.beginAggregateCpuSample("HillsGen.getHeight");
double scaledX = x * POSITION_SCALE;
double scaledY = y * POSITION_SCALE;
- float rVal = gradientHeight(SEED, scaledX, scaledY) * VERTICAL_SCALE + HEIGHT_OFFSET;
+ float rVal = HillsGen.gradientHeight(SEED, scaledX, scaledY) * VERTICAL_SCALE + HEIGHT_OFFSET;
Globals.profiler.endCpuSample();
return rVal;
}
diff --git a/src/main/java/electrosphere/server/terrain/generation/heightmap/SeaFloorGen.java b/src/main/java/electrosphere/server/terrain/generation/heightmap/SeaFloorGen.java
new file mode 100644
index 00000000..0e9e863e
--- /dev/null
+++ b/src/main/java/electrosphere/server/terrain/generation/heightmap/SeaFloorGen.java
@@ -0,0 +1,26 @@
+package electrosphere.server.terrain.generation.heightmap;
+
+import electrosphere.util.noise.OpenSimplex2S;
+
+/**
+ * Generates a mild plain that would look like a seafloor
+ */
+public class SeaFloorGen implements HeightmapGenerator {
+
+ /**
+ * The scale of the noise
+ */
+ float noiseScale = 0.01f;
+
+ @Override
+ public float getHeight(long SEED, double x, double y) {
+ float noise = (float)OpenSimplex2S.noise2_ImproveX(SEED, x * noiseScale, y * noiseScale);
+ return noise;
+ }
+
+ @Override
+ public String getTag() {
+ return "seafloor";
+ }
+
+}
diff --git a/src/main/java/electrosphere/server/terrain/generation/interfaces/GenerationContext.java b/src/main/java/electrosphere/server/terrain/generation/interfaces/GenerationContext.java
new file mode 100644
index 00000000..7492193c
--- /dev/null
+++ b/src/main/java/electrosphere/server/terrain/generation/interfaces/GenerationContext.java
@@ -0,0 +1,37 @@
+package electrosphere.server.terrain.generation.interfaces;
+
+import electrosphere.game.server.world.ServerWorldData;
+
+/**
+ * The context the generation is happening in. Stores things like biomes to interpolate between.
+ */
+public class GenerationContext {
+
+ /**
+ * The world data for the realm we're generating for
+ */
+ ServerWorldData serverWorldData;
+
+ /**
+ * Constructor
+ */
+ public GenerationContext(){
+ }
+
+ /**
+ * Gets the world data for the server
+ * @return The world data
+ */
+ public ServerWorldData getServerWorldData(){
+ return serverWorldData;
+ }
+
+ /**
+ * Sets the world data for the context
+ * @param serverWorldData The world data
+ */
+ public void setServerWorldData(ServerWorldData serverWorldData){
+ this.serverWorldData = serverWorldData;
+ }
+
+}
diff --git a/src/main/java/electrosphere/server/terrain/generation/voxelphase/AnimeMountainsGen.java b/src/main/java/electrosphere/server/terrain/generation/voxelphase/AnimeMountainsGen.java
new file mode 100644
index 00000000..fb29ddd2
--- /dev/null
+++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/AnimeMountainsGen.java
@@ -0,0 +1,259 @@
+package electrosphere.server.terrain.generation.voxelphase;
+
+import electrosphere.engine.Globals;
+import electrosphere.game.data.biome.BiomeData;
+import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
+import electrosphere.server.terrain.generation.interfaces.GenerationContext;
+import io.github.studiorailgun.MathUtils;
+import io.github.studiorailgun.RandUtils;
+
+/**
+ * Generates anime-style mountains
+ */
+public class AnimeMountainsGen implements VoxelGenerator {
+
+ /**
+ * The width of the surface in number of voxels
+ */
+ public static final int SURFACE_VOXEL_WIDTH = 2;
+
+ /**
+ * Size of the large cells that generate mountains
+ */
+ public static final int LARGE_CELL_SIZE = 1024;
+
+ /**
+ * How much to sink the cell into the surface
+ */
+ public static final int CELL_VERTICAL_OFFSET = - (int)((LARGE_CELL_SIZE) * 2.5 / 5.0);
+
+ /**
+ * The variance in scale of mountains
+ */
+ public static final double MOUNTAIN_SCALE_VARIANCE = 0.2;
+
+ /**
+ * The width of the mountain
+ */
+ public static final double MOUNTAIN_WIDTH = 0.4;
+
+ /**
+ * The center x point of the cell
+ */
+ public static final double CELL_CENTER_X = 0.5;
+
+ /**
+ * The center y point of the cell
+ */
+ public static final double CELL_CENTER_Y = 0.5;
+
+ /**
+ * The center z point of the cell
+ */
+ public static final double CELL_CENTER_Z = 0.5;
+
+ /**
+ * Amount the vertical rotation offset can vary
+ */
+ public static final double VERTICAL_ROTATION_OFFSET_VARIANCE = 0.2;
+
+ @Override
+ public String getTag() {
+ return "animeMountain";
+ }
+
+ @Override
+ public void getVoxel(
+ GeneratedVoxel voxel,
+ int worldX, int worldY, int worldZ,
+ int chunkX, int chunkY, int chunkZ,
+ int stride, float surfaceHeight,
+ BiomeData surfaceBiome,
+ GenerationContext generationContext
+ ) {
+ Globals.profiler.beginAggregateCpuSample("AnimeMountainsGen.getVoxel");
+
+ double realX = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkX,worldX);
+ double realY = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkY,worldY);
+ double realZ = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkZ,worldZ);
+
+ double strideMultiplier = Math.pow(2,stride);
+ double heightDiff = realY - surfaceHeight;
+ double surfacePercent = AnimeMountainsGen.getSurfaceWeight(surfaceHeight,realY,strideMultiplier);
+ Globals.profiler.endCpuSample();
+ if(heightDiff < -strideMultiplier * SURFACE_VOXEL_WIDTH){
+ this.getSubsurfaceVoxel(
+ voxel,
+ worldX, worldY, worldZ,
+ chunkX, chunkY, chunkZ,
+ realX, realY, realZ,
+ surfacePercent,
+ surfaceHeight,
+ surfaceBiome
+ );
+ } else if(heightDiff > 0) {
+ this.getOverSurfaceVoxel(
+ voxel,
+ worldX, worldY, worldZ,
+ chunkX, chunkY, chunkZ,
+ realX, realY, realZ,-
+ surfacePercent,
+ surfaceHeight,
+ surfaceBiome
+ );
+ } else {
+ this.getSurfaceVoxel(
+ voxel,
+ worldX, worldY, worldZ,
+ chunkX, chunkY, chunkZ,
+ realX, realY, realZ,
+ surfacePercent,
+ surfaceHeight,
+ surfaceBiome
+ );
+ }
+ }
+
+
+ /**
+ * Gets the voxel on the surface
+ * @return The voxel
+ */
+ private void getSurfaceVoxel(
+ GeneratedVoxel voxel,
+ int worldX, int worldY, int worldZ,
+ int chunkX, int chunkY, int chunkZ,
+ double realX, double realY, double realZ,
+ double surfacePercent,
+ float surfaceHeight,
+ BiomeData surfaceBiome
+ ){
+ voxel.weight = (float)surfacePercent * 2 - 1;
+ voxel.type = 2;
+ }
+
+ /**
+ * Gets the voxel below the surface
+ * @return The voxel
+ */
+ private void getSubsurfaceVoxel(
+ GeneratedVoxel voxel,
+ int worldX, int worldY, int worldZ,
+ int chunkX, int chunkY, int chunkZ,
+ double realX, double realY, double realZ,
+ double surfacePercent,
+ float surfaceHeight,
+ BiomeData surfaceBiome
+ ){
+ if(realY < surfaceHeight - 5){
+ voxel.weight = 1;
+ voxel.type = 6;
+ } else {
+ voxel.weight = 1;
+ voxel.type = 1;
+ }
+ }
+
+ /**
+ * Gets the voxel above the service
+ * @return The voxel
+ */
+ private void getOverSurfaceVoxel(
+ GeneratedVoxel voxel,
+ int worldX, int worldY, int worldZ,
+ int chunkX, int chunkY, int chunkZ,
+ double realX, double realY, double realZ,
+ double surfacePercent,
+ float surfaceHeight,
+ BiomeData surfaceBiome
+ ){
+ //default voxel value
+ voxel.weight = -1;
+ voxel.type = 0;
+
+ //get the height above the surface
+ double heightAboveBaseSurface = realY - surfaceBiome.getSurfaceGenerationParams().getHeightOffset();
+ double offsetHeight = heightAboveBaseSurface - CELL_VERTICAL_OFFSET;
+
+ //calculated floored values
+ double x_i = Math.floor(realX / LARGE_CELL_SIZE);
+ double y_i = Math.floor(offsetHeight / LARGE_CELL_SIZE);
+ double z_i = Math.floor(realZ / LARGE_CELL_SIZE);
+
+ //only generate if you're on the first cell from the surface
+ if(y_i < 1){
+ //calculate values from which cell we're in
+ double rotationTheta = RandUtils.rand(x_i, z_i, 0) * Math.PI * 2;
+ // double mountainScale = MathUtils.rand(x_i, z_i, 1) * MOUNTAIN_SCALE_VARIANCE + (1.0 - (MOUNTAIN_SCALE_VARIANCE / 2.0));
+ // double verticalRotationOffset = MathUtils.rand(x_i, z_i, 2) * VERTICAL_ROTATION_OFFSET_VARIANCE;
+
+ //remainders of the point coordinates
+ double x_r = (realX / LARGE_CELL_SIZE) - x_i;
+ double y_r = (offsetHeight / LARGE_CELL_SIZE) - y_i;
+ double z_r = (realZ / LARGE_CELL_SIZE) - z_i;
+
+ //get the center of the cell
+ double cellCenterX = CELL_CENTER_X;
+ double cellCenterY = CELL_CENTER_Y;
+ double cellCenterZ = CELL_CENTER_Z;
+
+ //delta positions
+ double deltaX = (x_r - cellCenterX);
+ double deltaY = (y_r - cellCenterY);
+ double deltaZ = (z_r - cellCenterZ);
+
+ //rotate around the center
+ double rotX = deltaX * Math.cos(rotationTheta) + deltaZ * Math.sin(rotationTheta);
+ double rotY = deltaY;
+ double rotZ = - deltaX * Math.sin(rotationTheta) + deltaZ * Math.cos(rotationTheta);
+
+ //roation along the arctre
+ //ranged [0,2PI]
+ double rotationAlongArc = Math.atan2(rotY,rotX);
+ //ranges [0,1]
+ // double rotationPercent = rotationAlongArc / (Math.PI * 2.0);
+
+
+ //calculate values from where we are WITHIN the cell
+ // double voxelGamma = Math.atan2(
+ // x_r - cellCenterX,
+ // z_r - cellCenterZ
+ // ) + Math.PI * 2.0;
+ // double voxelTheta = Math.atan2(y_r - cellCenterY, MathUtils.dist(x_r,z_r,cellCenterX,cellCenterZ));
+ double distanceFromCenter = MathUtils.dist(rotX,rotY,0,0);
+ double distanceFromArcCenter = Math.sqrt(rotZ*rotZ);
+
+ //target distance from center
+ double targetDistanceFromArcCenter = Math.sin(rotationAlongArc) * 0.3;
+ double targetArcRadius = 0.6;
+ double targetArcRadiusWidth = Math.sin(rotationAlongArc) * 0.03;
+
+
+ if(
+ // voxelTheta > 0 &&
+ // (voxelGamma - Math.PI/2) < Math.PI &&
+ // voxelTheta > Math.max(Math.sin(voxelGamma),0) &&
+ // voxelTheta > 0.4 * Math.max(Math.sin(voxelGamma),0) &&
+ distanceFromCenter > targetArcRadius - targetArcRadiusWidth &&
+ distanceFromCenter < targetArcRadius + targetArcRadiusWidth &&
+ distanceFromArcCenter < targetDistanceFromArcCenter
+ ){
+ voxel.weight = 1.0f;
+ voxel.type = 1;
+ }
+ }
+
+ }
+
+ /**
+ * Calculates the weight of a voxel on the surface based on the surface height, the position of the voxel, and the stride multiplier
+ * @param surfaceHeight The surface height
+ * @param realPosY The position of the voxel
+ * @param strideMultiplier The stride multiplier
+ * @return The weight of the voxel
+ */
+ private static double getSurfaceWeight(double surfaceHeight, double realPosY, double strideMultiplier){
+ return ((surfaceHeight - realPosY) / strideMultiplier);
+ }
+
+}
diff --git a/src/main/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGen.java b/src/main/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGen.java
new file mode 100644
index 00000000..c6d9b0a3
--- /dev/null
+++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGen.java
@@ -0,0 +1,146 @@
+package electrosphere.server.terrain.generation.voxelphase;
+
+import electrosphere.engine.Globals;
+import electrosphere.game.data.biome.BiomeData;
+import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
+import electrosphere.server.terrain.generation.interfaces.GenerationContext;
+
+/**
+ * Generates voxels for a hill
+ */
+public class HillsVoxelGen implements VoxelGenerator {
+
+ /**
+ * The width of the surface in number of voxels
+ */
+ public static final int SURFACE_VOXEL_WIDTH = 2;
+
+
+ @Override
+ public String getTag(){
+ return "hills";
+ }
+
+ @Override
+ public void getVoxel(
+ GeneratedVoxel voxel,
+ int worldX, int worldY, int worldZ,
+ int chunkX, int chunkY, int chunkZ,
+ int stride,
+ float surfaceHeight,
+ BiomeData surfaceBiome,
+ GenerationContext generationContext
+ ){
+ Globals.profiler.beginAggregateCpuSample("HillsVoxelGen.getVoxel");
+
+ double realX = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkX,worldX);
+ double realY = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkY,worldY);
+ double realZ = generationContext.getServerWorldData().convertVoxelToRealSpace(chunkZ,worldZ);
+
+ double strideMultiplier = Math.pow(2,stride);
+ double heightDiff = realY - surfaceHeight;
+ double surfacePercent = HillsVoxelGen.getSurfaceWeight(surfaceHeight,realY,strideMultiplier);
+ Globals.profiler.endCpuSample();
+ if(heightDiff < -strideMultiplier * SURFACE_VOXEL_WIDTH){
+ this.getSubsurfaceVoxel(
+ voxel,
+ worldX, worldY, worldZ,
+ chunkX, chunkY, chunkZ,
+ realX, realY, realZ,
+ surfacePercent,
+ surfaceHeight,
+ surfaceBiome
+ );
+ } else if(heightDiff > 0) {
+ this.getOverSurfaceVoxel(
+ voxel,
+ worldX, worldY, worldZ,
+ chunkX, chunkY, chunkZ,
+ realX, realY, realZ,-
+ surfacePercent,
+ surfaceHeight,
+ surfaceBiome
+ );
+ } else {
+ this.getSurfaceVoxel(
+ voxel,
+ worldX, worldY, worldZ,
+ chunkX, chunkY, chunkZ,
+ realX, realY, realZ,
+ surfacePercent,
+ surfaceHeight,
+ surfaceBiome
+ );
+ }
+ }
+
+ /**
+ * Gets the voxel on the surface
+ * @return The voxel
+ */
+ private void getSurfaceVoxel(
+ GeneratedVoxel voxel,
+ int worldX, int worldY, int worldZ,
+ int chunkX, int chunkY, int chunkZ,
+ double realX, double realY, double realZ,
+ double surfacePercent,
+ float surfaceHeight,
+ BiomeData surfaceBiome
+ ){
+ voxel.weight = (float)surfacePercent * 2 - 1;
+ voxel.type = 2;
+ }
+
+ /**
+ * Gets the voxel below the surface
+ * @return The voxel
+ */
+ private void getSubsurfaceVoxel(
+ GeneratedVoxel voxel,
+ int worldX, int worldY, int worldZ,
+ int chunkX, int chunkY, int chunkZ,
+ double realX, double realY, double realZ,
+ double surfacePercent,
+ float surfaceHeight,
+ BiomeData surfaceBiome
+ ){
+ if(realY < surfaceHeight - 5){
+ voxel.weight = 1;
+ voxel.type = 6;
+ } else {
+ voxel.weight = 1;
+ voxel.type = 1;
+ }
+ }
+
+ /**
+ * Gets the voxel above the service
+ * @return The voxel
+ */
+ private void getOverSurfaceVoxel(
+ GeneratedVoxel voxel,
+ int worldX, int worldY, int worldZ,
+ int chunkX, int chunkY, int chunkZ,
+ double realX, double realY, double realZ,
+ double surfacePercent,
+ float surfaceHeight,
+ BiomeData surfaceBiome
+ ){
+ voxel.weight = -1;
+ voxel.type = 0;
+ }
+
+ /**
+ * Calculates the weight of a voxel on the surface based on the surface height, the position of the voxel, and the stride multiplier
+ * @param surfaceHeight The surface height
+ * @param realPosY The position of the voxel
+ * @param strideMultiplier The stride multiplier
+ * @return The weight of the voxel
+ */
+ protected static double getSurfaceWeight(double surfaceHeight, double realPosY, double strideMultiplier){
+ return ((surfaceHeight - realPosY) / strideMultiplier);
+ }
+
+
+
+}
diff --git a/src/main/java/electrosphere/server/terrain/generation/voxelphase/VoxelGenerator.java b/src/main/java/electrosphere/server/terrain/generation/voxelphase/VoxelGenerator.java
new file mode 100644
index 00000000..c0030c5b
--- /dev/null
+++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/VoxelGenerator.java
@@ -0,0 +1,45 @@
+package electrosphere.server.terrain.generation.voxelphase;
+
+import electrosphere.game.data.biome.BiomeData;
+import electrosphere.server.terrain.generation.interfaces.GeneratedVoxel;
+import electrosphere.server.terrain.generation.interfaces.GenerationContext;
+
+
+/**
+ * Used for generating voxels
+ */
+public interface VoxelGenerator {
+
+
+ /**
+ * Gets the tag of the generator
+ * @return The tag
+ */
+ public String getTag();
+
+
+ /**
+ * Gets the value for a chunk
+ * @param voxel The voxel to fill
+ * @param worldX The world x pos
+ * @param worldY The world y pos
+ * @param worldZ The world z pos
+ * @param chunkX The chunk x pos
+ * @param chunkY The chunk y pos
+ * @param chunkZ The chunk z pos
+ * @param stride The stride of the data
+ * @param surfaceHeight The height of the surface at x,z
+ * @param surfaceBiome The surface biome of the chunk
+ * @param generationContext The generation context
+ */
+ public void getVoxel(
+ GeneratedVoxel voxel,
+ int worldX, int worldY, int worldZ,
+ int chunkX, int chunkY, int chunkZ,
+ int stride,
+ float surfaceHeight,
+ BiomeData surfaceBiome,
+ GenerationContext generationContext
+ );
+
+}
diff --git a/src/main/java/electrosphere/server/terrain/manager/ServerTerrainChunk.java b/src/main/java/electrosphere/server/terrain/manager/ServerTerrainChunk.java
index d64d0ce0..88ca4a94 100644
--- a/src/main/java/electrosphere/server/terrain/manager/ServerTerrainChunk.java
+++ b/src/main/java/electrosphere/server/terrain/manager/ServerTerrainChunk.java
@@ -80,6 +80,18 @@ public class ServerTerrainChunk {
this.values = values;
}
+ /**
+ * Constructor
+ * @param worldX The world position x coordinate
+ * @param worldY The world position y coordinate
+ * @param worldZ The world position z coordinate
+ */
+ public ServerTerrainChunk(int worldX, int worldY, int worldZ){
+ this.worldX = worldX;
+ this.worldY = worldY;
+ this.worldZ = worldZ;
+ }
+
/**
* Gets the world position x coordinate
* @return The x coordinate
@@ -201,5 +213,31 @@ public class ServerTerrainChunk {
public int getHomogenousValue(){
return homogenousValue;
}
+
+ /**
+ * Sets the weights of the chunk
+ * @param weights The weights
+ */
+ public void setWeights(float[][][] weights) {
+ this.weights = weights;
+ }
+
+ /**
+ * Sets the values of the chunk
+ * @param values The values
+ */
+ public void setValues(int[][][] values) {
+ this.values = values;
+ }
+
+ /**
+ * Sets the homogenous value
+ * @param homogenousValue The homogenous value
+ */
+ public void setHomogenousValue(int homogenousValue) {
+ this.homogenousValue = homogenousValue;
+ }
+
+
}
diff --git a/src/test/java/electrosphere/client/terrain/cells/ClientDrawCellManagerTests.java b/src/test/java/electrosphere/client/terrain/cells/ClientDrawCellManagerTests.java
index edc68deb..942ba843 100644
--- a/src/test/java/electrosphere/client/terrain/cells/ClientDrawCellManagerTests.java
+++ b/src/test/java/electrosphere/client/terrain/cells/ClientDrawCellManagerTests.java
@@ -40,9 +40,11 @@ public class ClientDrawCellManagerTests {
Vector3i playerPos = new Vector3i(0,0,0);
WorldOctTreeNode node = WorldOctTreeNode.constructorForTests(manager.chunkTree, 1, new Vector3i(16,0,0), new Vector3i(32,16,16));
node.setLeaf(true);
- node.setData(DrawCell.generateTerrainCell(new Vector3i(0,0,0),3));
+ node.setData(DrawCell.generateTerrainCell(new Vector3i(16,0,0),3));
- assertTrue(manager.shouldSplit(playerPos, node, 0));
+ boolean shouldBeTrue = node.getParent() != null;
+
+ assertEquals(shouldBeTrue,manager.shouldSplit(playerPos, node, 0));
//cleanup
Main.shutdown();
diff --git a/src/test/java/electrosphere/server/terrain/generation/TestGenerationChunkGeneratorTests.java b/src/test/java/electrosphere/server/terrain/generation/TestGenerationChunkGeneratorTests.java
deleted file mode 100644
index e0e5e542..00000000
--- a/src/test/java/electrosphere/server/terrain/generation/TestGenerationChunkGeneratorTests.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package electrosphere.server.terrain.generation;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-import electrosphere.test.annotations.FastTest;
-import electrosphere.test.annotations.UnitTest;
-
-/**
- * Unit tests for the test generation chunk generator
- */
-public class TestGenerationChunkGeneratorTests {
-
- @UnitTest
- @FastTest
- public void getSurfaceWeight_ValueTests(){
- assertEquals(0.5,TestGenerationChunkGenerator.getSurfaceWeight(0.5, 0, 1));
- assertEquals(0.1,TestGenerationChunkGenerator.getSurfaceWeight(0.1, 0, 1));
- assertEquals(0.9,TestGenerationChunkGenerator.getSurfaceWeight(0.9, 0, 1));
- assertEquals(0.95,TestGenerationChunkGenerator.getSurfaceWeight(1.9, 0, 2));
- }
-
-}
diff --git a/src/test/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGenTests.java b/src/test/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGenTests.java
new file mode 100644
index 00000000..62ec489a
--- /dev/null
+++ b/src/test/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGenTests.java
@@ -0,0 +1,22 @@
+package electrosphere.server.terrain.generation.voxelphase;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import electrosphere.test.annotations.FastTest;
+import electrosphere.test.annotations.UnitTest;
+
+/**
+ * Unit tests for the test generation chunk generator
+ */
+public class HillsVoxelGenTests {
+
+ @UnitTest
+ @FastTest
+ public void getSurfaceWeight_ValueTests(){
+ assertEquals(0.5,HillsVoxelGen.getSurfaceWeight(0.5, 0, 1));
+ assertEquals(0.1,HillsVoxelGen.getSurfaceWeight(0.1, 0, 1));
+ assertEquals(0.9,HillsVoxelGen.getSurfaceWeight(0.9, 0, 1));
+ assertEquals(0.95,HillsVoxelGen.getSurfaceWeight(1.9, 0, 2));
+ }
+
+}