From aa34ea4db61223654a857b6bb155b01a2fb188b0 Mon Sep 17 00:00:00 2001 From: austin Date: Fri, 29 Nov 2024 16:19:39 -0500 Subject: [PATCH] biome surface blending --- docs/src/progress/renderertodo.md | 3 + .../game/server/world/ServerWorldData.java | 31 +++ .../content/ServerContentGenerator.java | 2 +- .../datacell/GriddedDataCellManager.java | 2 +- .../terrain/generation/JSChunkGenerator.java | 4 +- .../TestGenerationChunkGenerator.java | 201 ++++++++++++++---- .../voxelphase/AnimeMountainsGen.java | 8 +- .../generation/voxelphase/HillsVoxelGen.java | 8 +- .../voxelphase/MountainVoxelGen.java | 8 +- .../generation/voxelphase/NoiseVoxelGen.java | 2 +- .../generation/voxelphase/VoxelGenerator.java | 2 +- .../server/terrain/models/TerrainModel.java | 42 +++- 12 files changed, 251 insertions(+), 62 deletions(-) diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 52a79ea3..530bd330 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1173,6 +1173,9 @@ Allow variable collision bits for collidable entities Autodisable terrain colliders Lower grass radius Work on diagnosing data cell misalignment with entities +Fix gridded data cell manager loops iterating incorrectly +Implement multi-biome sampling for surface heightmap +Nearest biome sampling for content generation # TODO diff --git a/src/main/java/electrosphere/game/server/world/ServerWorldData.java b/src/main/java/electrosphere/game/server/world/ServerWorldData.java index d32d4831..7a0668e8 100644 --- a/src/main/java/electrosphere/game/server/world/ServerWorldData.java +++ b/src/main/java/electrosphere/game/server/world/ServerWorldData.java @@ -270,6 +270,37 @@ public class ServerWorldData { convertRealToChunkSpace(position.z) ); } + + /** + * Converts a world coordinate to a macro scale coordinate + * @param worldPos The world position + * @return The macro scale position + */ + public Vector3i convertWorldToMacroScale(Vector3i worldPos){ + return new Vector3i( + worldPos.x / this.serverTerrainManager.getModel().getMacroDataScale(), + worldPos.y / this.serverTerrainManager.getModel().getMacroDataScale(), + worldPos.z / this.serverTerrainManager.getModel().getMacroDataScale() + ); + } + + /** + * Converts a world coordinate to a macro scale coordinate + * @param worldPos The world position + * @return The macro scale position + */ + public int convertWorldToMacroScale(int worldPos){ + return worldPos / this.serverTerrainManager.getModel().getMacroDataScale(); + } + + /** + * Clamps the world position to the floored macro value in world pos + * @param worldPos The world position + * @return The floor macro value in world pos + */ + public int clampWorldToMacro(int worldPos){ + return (worldPos / this.serverTerrainManager.getModel().getMacroDataScale()) * this.serverTerrainManager.getModel().getMacroDataScale(); + } /** * Gets the terrain manager for this world diff --git a/src/main/java/electrosphere/server/content/ServerContentGenerator.java b/src/main/java/electrosphere/server/content/ServerContentGenerator.java index caf9fd37..7f9a4c47 100644 --- a/src/main/java/electrosphere/server/content/ServerContentGenerator.java +++ b/src/main/java/electrosphere/server/content/ServerContentGenerator.java @@ -55,7 +55,7 @@ public class ServerContentGenerator { //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); + biome = realm.getServerWorldData().getServerTerrainManager().getModel().getClosestSurfaceBiome(worldPos.x, worldPos.z); } List foliageDescriptions = biome.getSurfaceGenerationParams().getFoliageDescriptions(); if(foliageDescriptions != null){ diff --git a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java index 411693f4..017e318b 100644 --- a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java @@ -332,7 +332,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager //Add to cells that are in range for(int x = newPosition.x - playerSimulationRadius + 1; x < newPosition.x + playerSimulationRadius; x++){ for(int y = newPosition.y - playerSimulationRadius + 1; y < newPosition.y + playerSimulationRadius; y++){ - for(int z = newPosition.x - playerSimulationRadius + 1; z < newPosition.z + playerSimulationRadius; z++){ + for(int z = newPosition.z - playerSimulationRadius + 1; z < newPosition.z + playerSimulationRadius; z++){ if(this.canCreateCell(x,y,z) && this.shouldContainPlayer(new Vector3i(x,y,z), newPosition, playerSimulationRadius)){ Vector3i targetPos = new Vector3i(x,y,z); if(groundDataCells.get(this.getServerDataCellKey(targetPos)) != null){ diff --git a/src/main/java/electrosphere/server/terrain/generation/JSChunkGenerator.java b/src/main/java/electrosphere/server/terrain/generation/JSChunkGenerator.java index b6126b1d..f58039bb 100644 --- a/src/main/java/electrosphere/server/terrain/generation/JSChunkGenerator.java +++ b/src/main/java/electrosphere/server/terrain/generation/JSChunkGenerator.java @@ -120,7 +120,7 @@ public class JSChunkGenerator implements ChunkGenerator { try { //biome of the current chunk - BiomeData surfaceBiome = this.terrainModel.getSurfaceBiome(worldX, worldZ); + BiomeData surfaceBiome = this.terrainModel.getClosestSurfaceBiome(worldX, worldZ); BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams(); HeightmapGenerator heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag()); @@ -218,7 +218,7 @@ public class JSChunkGenerator implements ChunkGenerator { @Override public double getElevation(int worldX, int worldZ, int chunkX, int chunkZ){ - BiomeData surfaceBiome = this.terrainModel.getSurfaceBiome(worldX, worldZ); + BiomeData surfaceBiome = this.terrainModel.getClosestSurfaceBiome(worldX, worldZ); BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams(); HeightmapGenerator heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag()); diff --git a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java index b8827761..19270ac8 100644 --- a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java +++ b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java @@ -134,40 +134,21 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { int[][][] values = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; try { - //biome of the current chunk - BiomeData surfaceBiome = this.terrainModel.getSurfaceBiome(worldX, worldZ); - - BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams(); - HeightmapGenerator heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag()); - heightmapGen = this.tagHeightmapMap.get("hills"); - if(heightmapGen == null){ - throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag()); - } //stride value int strideValue = (int)Math.pow(2,stride); //presolve heightfield - float[][] heightfield = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; - for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){ - for(int z = 0; z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; z++){ - int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION); - int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION); - int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; - int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; - heightfield[x][z] = heightmapGen.getHeight( - this.terrainModel.getSeed(), - this.serverWorldData.convertVoxelToRealSpace(finalChunkX, finalWorldX), - this.serverWorldData.convertVoxelToRealSpace(finalChunkZ, finalWorldZ) - ); - } - } + double[][] heightfield = new double[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; + BiomeData[][] surfaceBiomeMap = new BiomeData[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; + this.populateElevation(heightfield,surfaceBiomeMap,worldX,worldZ,strideValue); + - float[][] gradientField = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; + double[][] gradientField = new double[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE]; for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){ for(int z = 0; z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; z++){ - float deltaX = 0; - float deltaZ = 0; + double deltaX = 0; + double deltaZ = 0; if(x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 1){ deltaX = Math.abs(heightfield[x][z] - heightfield[x+1][z]); } else { @@ -199,8 +180,9 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION); int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; double realZ = generationContext.getServerWorldData().convertVoxelToRealSpace(finalChunkZ,finalWorldZ); - float surfaceHeight = heightfield[x][z]; - float gradient = gradientField[x][z]; + double surfaceHeight = heightfield[x][z]; + double gradient = gradientField[x][z]; + BiomeData surfaceBiome = surfaceBiomeMap[x][z]; for(int y = 0; y < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; y++){ int finalWorldY = worldY + ((y * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION); @@ -249,21 +231,158 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { return rVal; } + /** + * Populates the heightfield + * @param heightfield The heightfield to populate + * @param surfaceBiomeMap The surface biome map + * @param worldX The world x position + * @param worldZ The world z position + * @param strideValue The stride value + */ + private void populateElevation(double[][] heightfield, BiomeData[][] surfaceBiomeMap, int worldX, int worldZ, int strideValue){ + for(int x = 0; x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; x++){ + for(int z = 0; z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; z++){ + int finalWorldX = worldX + ((x * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION); + int finalWorldZ = worldZ + ((z * strideValue) / ServerTerrainChunk.CHUNK_DIMENSION); + int finalChunkX = (x * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; + int finalChunkZ = (z * strideValue) % ServerTerrainChunk.CHUNK_DIMENSION; + + heightfield[x][z] = this.getMultisampleElevation(finalWorldX, finalWorldZ, finalChunkX, finalChunkZ); + + //calculate real pos + double realX = serverWorldData.convertVoxelToRealSpace(finalChunkX, finalWorldX); + double realZ = serverWorldData.convertVoxelToRealSpace(finalChunkZ, finalWorldZ); + + //clamped macro pos + int macroDataScale = terrainModel.getMacroDataScale(); + double macroWorldPosX = serverWorldData.convertWorldToReal(serverWorldData.clampWorldToMacro(finalWorldX)); + double macroWorldPosZ = serverWorldData.convertWorldToReal(serverWorldData.clampWorldToMacro(finalWorldZ)); + double macroWidth = this.terrainModel.getMacroWidthInRealTerms(); + double percent1 = (realX - macroWorldPosX) / macroWidth; + double percent2 = (realZ - macroWorldPosZ) / macroWidth; + + //solve dominant surface biome + if(percent1 > 0.5){ + if(percent2 > 0.5){ + surfaceBiomeMap[x][z] = this.terrainModel.getMacroData(finalWorldX / macroDataScale + 1, finalWorldZ / macroDataScale + 1); + } else { + surfaceBiomeMap[x][z] = this.terrainModel.getMacroData(finalWorldX / macroDataScale + 1, finalWorldZ / macroDataScale); + } + } else { + if(percent2 > 0.5){ + surfaceBiomeMap[x][z] = this.terrainModel.getMacroData(finalWorldX / macroDataScale, finalWorldZ / macroDataScale + 1); + } else { + surfaceBiomeMap[x][z] = this.terrainModel.getMacroData(finalWorldX / macroDataScale, finalWorldZ / macroDataScale); + } + } + } + } + } + + /** + * Gets the elevation of a given position by sampling all four surrounding biome generators + * @param finalWorldX The world x coordinate + * @param finalWorldZ The world z coordinate + * @param finalChunkX The chunk x coordinate + * @param finalChunkZ The chunk z coordinate + * @return The elevation of the world at that position + */ + private double getMultisampleElevation(int finalWorldX, int finalWorldZ, int finalChunkX, int finalChunkZ){ + double rVal = 0; + + //biome of the current chunk + double weight = 0; + BiomeData surfaceBiome = null; + BiomeSurfaceGenerationParams surfaceParams = null; + HeightmapGenerator heightmapGen = null; + + //calculate real pos + double realX = serverWorldData.convertVoxelToRealSpace(finalChunkX, finalWorldX); + double realZ = serverWorldData.convertVoxelToRealSpace(finalChunkZ, finalWorldZ); + + //clamped macro pos + int macroDataScale = terrainModel.getMacroDataScale(); + double macroWorldPosX = serverWorldData.convertWorldToReal(serverWorldData.clampWorldToMacro(finalWorldX)); + double macroWorldPosZ = serverWorldData.convertWorldToReal(serverWorldData.clampWorldToMacro(finalWorldZ)); + double macroWidth = this.terrainModel.getMacroWidthInRealTerms(); + double percent1 = (realX - macroWorldPosX) / macroWidth; + double percent2 = (realZ - macroWorldPosZ) / macroWidth; + + //sample 1 + { + weight = (1.0 - percent1) * (1.0 - percent2); + surfaceBiome = this.terrainModel.getMacroData(finalWorldX / macroDataScale, finalWorldZ / macroDataScale); + surfaceParams = surfaceBiome.getSurfaceGenerationParams(); + heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag()); + if(heightmapGen == null){ + throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag()); + } + + rVal = rVal + heightmapGen.getHeight( + this.terrainModel.getSeed(), + realX, + realZ + ) * weight; + } + + + //sample 2 + { + weight = percent1 * (1.0 - percent2); + surfaceBiome = this.terrainModel.getMacroData(finalWorldX / macroDataScale + 1, finalWorldZ / macroDataScale); + surfaceParams = surfaceBiome.getSurfaceGenerationParams(); + heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag()); + if(heightmapGen == null){ + throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag()); + } + + rVal = rVal + heightmapGen.getHeight( + this.terrainModel.getSeed(), + realX, + realZ + ) * weight; + } + + //sample 3 + { + weight = (1.0 - percent1) * percent2; + surfaceBiome = this.terrainModel.getMacroData(finalWorldX / macroDataScale, finalWorldZ / macroDataScale + 1); + surfaceParams = surfaceBiome.getSurfaceGenerationParams(); + heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag()); + if(heightmapGen == null){ + throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag()); + } + + rVal = rVal + heightmapGen.getHeight( + this.terrainModel.getSeed(), + realX, + realZ + ) * weight; + } + + //sample 4 + { + weight = percent1 * percent2; + surfaceBiome = this.terrainModel.getMacroData(finalWorldX / macroDataScale + 1, finalWorldZ / macroDataScale + 1); + surfaceParams = surfaceBiome.getSurfaceGenerationParams(); + heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag()); + if(heightmapGen == null){ + throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag()); + } + + rVal = rVal+ heightmapGen.getHeight( + this.terrainModel.getSeed(), + realX, + realZ + ) * weight; + } + + return rVal; + } + @Override public double getElevation(int worldX, int worldZ, int chunkX, int chunkZ){ - BiomeData surfaceBiome = this.terrainModel.getSurfaceBiome(worldX, worldZ); - - BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams(); - HeightmapGenerator heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag()); - if(heightmapGen == null){ - throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag()); - } - double rVal = heightmapGen.getHeight( - this.terrainModel.getSeed(), - this.serverWorldData.convertVoxelToRealSpace(chunkX, worldX), - this.serverWorldData.convertVoxelToRealSpace(chunkZ, worldZ) - ); - return rVal; + return this.getMultisampleElevation(worldX,worldZ,chunkX,chunkZ); } @Override diff --git a/src/main/java/electrosphere/server/terrain/generation/voxelphase/AnimeMountainsGen.java b/src/main/java/electrosphere/server/terrain/generation/voxelphase/AnimeMountainsGen.java index 3dd6ce8d..a180168e 100644 --- a/src/main/java/electrosphere/server/terrain/generation/voxelphase/AnimeMountainsGen.java +++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/AnimeMountainsGen.java @@ -68,7 +68,7 @@ public class AnimeMountainsGen implements VoxelGenerator { int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, - int stride, float surfaceHeight, float surfaceGradient, + int stride, double surfaceHeight, double surfaceGradient, BiomeData surfaceBiome, GenerationContext generationContext ) { @@ -122,7 +122,7 @@ public class AnimeMountainsGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, double surfacePercent, - float surfaceHeight, + double surfaceHeight, BiomeData surfaceBiome ){ voxel.weight = (float)surfacePercent * 2 - 1; @@ -139,7 +139,7 @@ public class AnimeMountainsGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, double surfacePercent, - float surfaceHeight, + double surfaceHeight, BiomeData surfaceBiome ){ if(realY < surfaceHeight - 5){ @@ -161,7 +161,7 @@ public class AnimeMountainsGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, double surfacePercent, - float surfaceHeight, + double surfaceHeight, BiomeData surfaceBiome ){ //default voxel value diff --git a/src/main/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGen.java b/src/main/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGen.java index 9b321782..6c6722dd 100644 --- a/src/main/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGen.java +++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGen.java @@ -28,7 +28,7 @@ public class HillsVoxelGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, int stride, - float surfaceHeight, float surfaceGradient, + double surfaceHeight, double surfaceGradient, BiomeData surfaceBiome, GenerationContext generationContext ){ @@ -81,7 +81,7 @@ public class HillsVoxelGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, double surfacePercent, - float surfaceHeight, + double surfaceHeight, BiomeData surfaceBiome ){ voxel.weight = (float)surfacePercent * 2 - 1; @@ -98,7 +98,7 @@ public class HillsVoxelGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, double surfacePercent, - float surfaceHeight, + double surfaceHeight, BiomeData surfaceBiome ){ if(realY < surfaceHeight - 5){ @@ -120,7 +120,7 @@ public class HillsVoxelGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, double surfacePercent, - float surfaceHeight, + double surfaceHeight, BiomeData surfaceBiome ){ voxel.weight = -1; diff --git a/src/main/java/electrosphere/server/terrain/generation/voxelphase/MountainVoxelGen.java b/src/main/java/electrosphere/server/terrain/generation/voxelphase/MountainVoxelGen.java index 93cbf1cf..df2d88d1 100644 --- a/src/main/java/electrosphere/server/terrain/generation/voxelphase/MountainVoxelGen.java +++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/MountainVoxelGen.java @@ -35,7 +35,7 @@ public class MountainVoxelGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, int stride, - float surfaceHeight, float surfaceGradient, + double surfaceHeight, double surfaceGradient, BiomeData surfaceBiome, GenerationContext generationContext ){ @@ -88,7 +88,7 @@ public class MountainVoxelGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, double surfacePercent, - float surfaceHeight, float surfaceGradient, + double surfaceHeight, double surfaceGradient, BiomeData surfaceBiome ){ voxel.weight = (float)surfacePercent * 2 - 1; @@ -112,7 +112,7 @@ public class MountainVoxelGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, double surfacePercent, - float surfaceHeight, float surfaceGradient, + double surfaceHeight, double surfaceGradient, BiomeData surfaceBiome ){ if(realY < surfaceHeight - 5){ @@ -134,7 +134,7 @@ public class MountainVoxelGen implements VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, double surfacePercent, - float surfaceHeight, float surfaceGradient, + double surfaceHeight, double surfaceGradient, BiomeData surfaceBiome ){ voxel.weight = -1; diff --git a/src/main/java/electrosphere/server/terrain/generation/voxelphase/NoiseVoxelGen.java b/src/main/java/electrosphere/server/terrain/generation/voxelphase/NoiseVoxelGen.java index 88ab62a3..35dcb474 100644 --- a/src/main/java/electrosphere/server/terrain/generation/voxelphase/NoiseVoxelGen.java +++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/NoiseVoxelGen.java @@ -46,7 +46,7 @@ public class NoiseVoxelGen implements VoxelGenerator { int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, - int stride, float surfaceHeight, float surfaceGradient, + int stride, double surfaceHeight, double surfaceGradient, BiomeData surfaceBiome, GenerationContext generationContext ) { double strideMultiplier = Math.pow(2,stride); diff --git a/src/main/java/electrosphere/server/terrain/generation/voxelphase/VoxelGenerator.java b/src/main/java/electrosphere/server/terrain/generation/voxelphase/VoxelGenerator.java index 8af2f905..f289bdf9 100644 --- a/src/main/java/electrosphere/server/terrain/generation/voxelphase/VoxelGenerator.java +++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/VoxelGenerator.java @@ -39,7 +39,7 @@ public interface VoxelGenerator { int chunkX, int chunkY, int chunkZ, double realX, double realY, double realZ, int stride, - float surfaceHeight, float surfaceGradient, + double surfaceHeight, double surfaceGradient, BiomeData surfaceBiome, GenerationContext generationContext ); diff --git a/src/main/java/electrosphere/server/terrain/models/TerrainModel.java b/src/main/java/electrosphere/server/terrain/models/TerrainModel.java index 12beadab..865964bd 100644 --- a/src/main/java/electrosphere/server/terrain/models/TerrainModel.java +++ b/src/main/java/electrosphere/server/terrain/models/TerrainModel.java @@ -3,6 +3,7 @@ package electrosphere.server.terrain.models; import electrosphere.engine.Globals; import electrosphere.game.data.biome.BiomeData; import electrosphere.server.terrain.generation.TestGenerationChunkGenerator; +import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.util.annotation.Exclude; /** @@ -129,6 +130,7 @@ public class TerrainModel { rVal.biome[x][z] = TestGenerationChunkGenerator.DEFAULT_BIOME_INDEX; } } + rVal.biome[1][0] = 0; return rVal; } @@ -463,9 +465,26 @@ public class TerrainModel { * @param worldZ The world Z * @return The biome */ - public BiomeData getSurfaceBiome(int worldX, int worldZ){ - int macroX = worldX / macroDataScale; - int macroZ = worldZ / macroDataScale; + public BiomeData getClosestSurfaceBiome(int worldX, int worldZ){ + //essentially, select the closest macro data point, not just floor + int offsetX = worldX % macroDataScale > (macroDataScale / 2.0) ? 1 : 0; + int offsetZ = worldZ % macroDataScale > (macroDataScale / 2.0) ? 1 : 0; + + + int macroX = worldX / macroDataScale + offsetX; + int macroZ = worldZ / macroDataScale + offsetZ; + int surfaceBiomeIndex = this.biome[macroX][macroZ]; + BiomeData biome = Globals.gameConfigCurrent.getBiomeMap().getBiomeByIndex(surfaceBiomeIndex); + return biome; + } + + /** + * Gets the surface biome for a given macro position + * @param worldX The macro X + * @param worldZ The macro Z + * @return The biome + */ + public BiomeData getMacroData(int macroX, int macroZ){ int surfaceBiomeIndex = this.biome[macroX][macroZ]; BiomeData biome = Globals.gameConfigCurrent.getBiomeMap().getBiomeByIndex(surfaceBiomeIndex); return biome; @@ -497,5 +516,22 @@ public class TerrainModel { public void setMacroDataScale(int scale){ this.macroDataScale = scale; } + + /** + * Gets the scale of the macro data + * @return The scale + */ + public int getMacroDataScale(){ + return this.macroDataScale; + } + + /** + * Gets the width of the macro data in real terms + * @return The width of the macro data in real terms + */ + public double getMacroWidthInRealTerms(){ + return this.macroDataScale * ServerTerrainChunk.CHUNK_DIMENSION; + } + }