diff --git a/assets/Data/entity/objects/furniture.json b/assets/Data/entity/objects/furniture.json index 8114af4f..0f4e935b 100644 --- a/assets/Data/entity/objects/furniture.json +++ b/assets/Data/entity/objects/furniture.json @@ -70,7 +70,8 @@ "rotW": 1, "offsetX" : 0.0, "offsetY" : 0.5, - "offsetZ" : 0.0 + "offsetZ" : 0.0, + "kinematic" : true }, "interaction" : { "onInteract" : "menu", diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 010a74e4..7bc1de8e 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1056,6 +1056,11 @@ Update visuals on pine tree Mountain generation work Implement crafting Fix image panel test +Add explicit kinematic flag in data +Fix hitbox destruction logic to not double-delete + +(11/17/2024) +Mountain generation work diff --git a/src/main/java/electrosphere/collision/PhysicsEntityUtils.java b/src/main/java/electrosphere/collision/PhysicsEntityUtils.java index 6cf1fa9e..d09d3b4f 100644 --- a/src/main/java/electrosphere/collision/PhysicsEntityUtils.java +++ b/src/main/java/electrosphere/collision/PhysicsEntityUtils.java @@ -110,6 +110,9 @@ public class PhysicsEntityUtils { if(physicsTemplate.isAngularlyStatic()){ Globals.clientSceneWrapper.getCollisionEngine().setAngularlyStatic(rigidBody, true); } + if(physicsTemplate.getKinematic()){ + Globals.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody); + } rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); @@ -170,6 +173,9 @@ public class PhysicsEntityUtils { if(physicsTemplate.isAngularlyStatic()){ Globals.clientSceneWrapper.getCollisionEngine().setAngularlyStatic(rigidBody, true); } + if(physicsTemplate.getKinematic()){ + Globals.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody); + } rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); @@ -232,6 +238,9 @@ public class PhysicsEntityUtils { if(physicsTemplate.isAngularlyStatic()){ Globals.clientSceneWrapper.getCollisionEngine().setAngularlyStatic(rigidBody, true); } + if(physicsTemplate.getKinematic()){ + Globals.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody); + } rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); @@ -317,6 +326,9 @@ public class PhysicsEntityUtils { if(physicsTemplate.isAngularlyStatic()){ realm.getCollisionEngine().setAngularlyStatic(rigidBody, true); } + if(physicsTemplate.getKinematic()){ + Globals.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody); + } rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); @@ -377,6 +389,9 @@ public class PhysicsEntityUtils { if(physicsTemplate.isAngularlyStatic()){ realm.getCollisionEngine().setAngularlyStatic(rigidBody, true); } + if(physicsTemplate.getKinematic()){ + Globals.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody); + } rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); @@ -439,6 +454,9 @@ public class PhysicsEntityUtils { if(physicsTemplate.isAngularlyStatic()){ realm.getCollisionEngine().setAngularlyStatic(rigidBody, true); } + if(physicsTemplate.getKinematic()){ + Globals.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody); + } rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); diff --git a/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java b/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java index c4ebf5f9..1a734122 100644 --- a/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java +++ b/src/main/java/electrosphere/engine/assetmanager/AssetDataStrings.java @@ -18,6 +18,12 @@ public class AssetDataStrings { public static final String MODEL_PARTICLE = "particleModel"; public static final String TEXTURE_PARTICLE = "particleTexture"; + /** + * UI textures + */ + public static final String UI_FRAME_TEXTURE_DEFAULT_1 = "Textures/ui/uiFrame1.png"; + public static final String UI_FRAME_TEXTURE_DEFAULT_2 = "Textures/ui/uiFrame2.png"; + /** * UI generic audio */ diff --git a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java index a7d36205..0edaf568 100644 --- a/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java +++ b/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java @@ -529,6 +529,7 @@ public class HitboxCollectionState { state = HitboxCollectionState.getHitboxState(entity); state.manager.deregisterHitbox(state); state.destroy(isServer); + entity.removeData(EntityDataStrings.HITBOX_DATA); } return state; } diff --git a/src/main/java/electrosphere/entity/types/item/ItemUtils.java b/src/main/java/electrosphere/entity/types/item/ItemUtils.java index 2c1f2cf2..dac02aeb 100644 --- a/src/main/java/electrosphere/entity/types/item/ItemUtils.java +++ b/src/main/java/electrosphere/entity/types/item/ItemUtils.java @@ -517,8 +517,6 @@ public class ItemUtils { //destroy physics //this deregisters from all four & unhooks rigid bodies from the physics runtime Globals.clientSceneWrapper.getCollisionEngine().destroyPhysics(item); - //destroy hitboxes - HitboxCollectionState.destroyHitboxState(item,false); //destroy graphics ClientEntityUtils.destroyEntity(item); } diff --git a/src/main/java/electrosphere/game/data/collidable/CollidableTemplate.java b/src/main/java/electrosphere/game/data/collidable/CollidableTemplate.java index ff30071c..f5c1a439 100644 --- a/src/main/java/electrosphere/game/data/collidable/CollidableTemplate.java +++ b/src/main/java/electrosphere/game/data/collidable/CollidableTemplate.java @@ -10,17 +10,54 @@ public class CollidableTemplate { */ String type; + /** + * The first dimension of the rigid body + */ float dimension1; + + /** + * The second dimension of the rigid body + */ float dimension2; + + /** + * The third dimension of the rigid body + */ float dimension3; + /** + * The x component of the quaternion controlling the offset rotation of the body + */ float rotX; + + /** + * The y component of the quaternion controlling the offset rotation of the body + */ float rotY; + + /** + * The z component of the quaternion controlling the offset rotation of the body + */ float rotZ; + + /** + * The w component of the quaternion controlling the offset rotation of the body + */ float rotW; + /** + * The x component of the vector controlling the offset position of the body + */ float offsetX; + + /** + * The y component of the vector controlling the offset position of the body + */ float offsetY; + + /** + * The z component of the vector controlling the offset position of the body + */ float offsetZ; /** @@ -43,6 +80,11 @@ public class CollidableTemplate { */ boolean angularlyStatic; + /** + * Controls whether the body is kinematic (infinite mass) or not + */ + boolean kinematic; + /** * The primitive shape type * @return The primitive shape @@ -51,42 +93,82 @@ public class CollidableTemplate { return type; } + /** + * Gets the first dimension of the rigid body + * @return The first dimension of the rigid body + */ public float getDimension1() { return dimension1; } + /** + * Gets the second dimension of the rigid body + * @return The second dimension of the rigid body + */ public float getDimension2() { return dimension2; } + /** + * Gets the third dimension of the rigid body + * @return The third dimension of the rigid body + */ public float getDimension3() { return dimension3; } + /** + * Gets the x component of the quaternion controlling the offset rotation of the body + * @return The x component of the quaternion controlling the offset rotation of the body + */ public float getRotX(){ return rotX; } + /** + * Gets the y component of the quaternion controlling the offset rotation of the body + * @return The y component of the quaternion controlling the offset rotation of the body + */ public float getRotY(){ return rotY; } + /** + * Gets the z component of the quaternion controlling the offset rotation of the body + * @return The z component of the quaternion controlling the offset rotation of the body + */ public float getRotZ(){ return rotZ; } + /** + * Gets the w component of the quaternion controlling the offset rotation of the body + * @return The w component of the quaternion controlling the offset rotation of the body + */ public float getRotW(){ return rotW; } + /** + * Gets the x component of the vector controlling the offset position of the body + * @return The x component of the vector controlling the offset position of the body + */ public float getOffsetX() { return offsetX; } + /** + * Gets the y component of the vector controlling the offset position of the body + * @return The y component of the vector controlling the offset position of the body + */ public float getOffsetY() { return offsetY; } + /** + * Gets the z component of the vector controlling the offset position of the body + * @return The z component of the vector controlling the offset position of the body + */ public float getOffsetZ() { return offsetZ; } @@ -123,30 +205,70 @@ public class CollidableTemplate { return this.angularlyStatic; } + /** + * Sets the first dimension of the rigid body + * @return The first dimension of the rigid body + */ public void setDimension1(float dimension1) { this.dimension1 = dimension1; } + /** + * Sets the second dimension of the rigid body + * @return The second dimension of the rigid body + */ public void setDimension2(float dimension2) { this.dimension2 = dimension2; } + /** + * Sets the third dimension of the rigid body + * @return The third dimension of the rigid body + */ public void setDimension3(float dimension3) { this.dimension3 = dimension3; } + /** + * Sets the x component of the vector controlling the offset position of the body + * @return The x component of the vector controlling the offset position of the body + */ public void setOffsetX(float offsetX) { this.offsetX = offsetX; } + /** + * Sets the y component of the vector controlling the offset position of the body + * @return The y component of the vector controlling the offset position of the body + */ public void setOffsetY(float offsetY) { this.offsetY = offsetY; } + /** + * Sets the z component of the vector controlling the offset position of the body + * @return The z component of the vector controlling the offset position of the body + */ public void setOffsetZ(float offsetZ) { this.offsetZ = offsetZ; } + /** + * Gets whether the body is kinematic (infinite mass) or not + * @return true if the body is kinematic, false otherwise + */ + public boolean getKinematic() { + return kinematic; + } + + /** + * Sets whether the body is kinematic (infinite mass) or not + * @param kinematic true if the body is kinematic, false otherwise + */ + public void setKinematic(boolean kinematic) { + this.kinematic = kinematic; + } + diff --git a/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java b/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java index e6d0be24..5b3f82e4 100644 --- a/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java +++ b/src/main/java/electrosphere/net/synchronization/transport/StateCollection.java @@ -3,7 +3,6 @@ package electrosphere.net.synchronization.transport; import electrosphere.entity.state.movement.editor.ServerEditorMovementTree; import electrosphere.entity.state.movement.editor.ClientEditorMovementTree; -import electrosphere.util.Utilities; import electrosphere.entity.state.equip.ServerToolbarState; import electrosphere.entity.state.equip.ClientToolbarState; import electrosphere.entity.state.stance.ServerStanceComponent; diff --git a/src/main/java/electrosphere/renderer/ui/elements/Window.java b/src/main/java/electrosphere/renderer/ui/elements/Window.java index 46f174f7..92373626 100644 --- a/src/main/java/electrosphere/renderer/ui/elements/Window.java +++ b/src/main/java/electrosphere/renderer/ui/elements/Window.java @@ -1,19 +1,16 @@ package electrosphere.renderer.ui.elements; -import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT; -import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT; -import static org.lwjgl.opengl.GL11.glClear; -import static org.lwjgl.opengl.GL11.glClearColor; - import java.util.LinkedList; import java.util.List; import org.joml.Vector3f; +import org.lwjgl.opengl.GL40; import org.lwjgl.util.yoga.YGLayout; import org.lwjgl.util.yoga.YGNode; import org.lwjgl.util.yoga.Yoga; import electrosphere.engine.Globals; +import electrosphere.engine.assetmanager.AssetDataStrings; import electrosphere.engine.signal.Signal.SignalType; import electrosphere.logger.LoggerInterface; import electrosphere.renderer.OpenGLState; @@ -35,38 +32,70 @@ import electrosphere.renderer.ui.events.NavigationEvent; */ public class Window implements DrawableElement, ContainerElement, NavigableElement { - static Vector3f color = new Vector3f(1.0f); + /** + * The color of the window + */ + Vector3f color = new Vector3f(1.0f); + /** + * The child elements of this window + */ List childList = new LinkedList(); + + /** + * The buffer to draw the contents of the window to + */ Framebuffer widgetBuffer; + + /** + * The material for the window + */ Material customMat = new Material(); + /** + * The position of buffer texture within the render call for the window itself + */ Vector3f texPosition = new Vector3f(0,0,0); + + /** + * The scale of buffer texture within the render call for the window itself + */ Vector3f texScale = new Vector3f(1,1,0); + /** + * The navigation callback for the window + */ NavigationEventCallback navCallback; - static final Vector3f windowDrawDebugColor = new Vector3f(1.0f,0.0f,0.0f); - /** * Default width of popups */ static final int DEFAULT_POPUP_WIDTH = 1000; + /** * Default height of popups */ static final int DEFAULT_POPUP_HEIGHT = 1000; - //controls whether to show window decorations (ie the frame) + /** + * Controls whether the decorations for the window draw or not + */ boolean showDecorations = true; - //Yoga node for controlling placement of the window on the screen - //IE, if you want to place a window in the upper right hand side of the screen, - //this node can be used to control placement alignment to accomplish that - //NOTE: It should always be set to the current size of the window (width, height) - //NOTE: It is updated every time the applyYoga function is called + /** + * Yoga node for controlling placement of the window on the screen + * IE, if you want to place a window in the upper right hand side of the screen, + * this node can be used to control placement alignment to accomplish that + * NOTE: It should always be set to the current size of the window (width, height) + * NOTE: It is updated every time the applyYoga function is called + */ long parentWindowYogaNode = -1; - + + /** + * The frame decoration texture path + */ + String frameDecoration = AssetDataStrings.UI_FRAME_TEXTURE_DEFAULT_1; + /** * Constructor * @param showDecorations @@ -186,12 +215,12 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme widgetBuffer.bind(openGLState); openGLState.glViewport(width, height); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + GL40.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + GL40.glClear(GL40.GL_COLOR_BUFFER_BIT | GL40.GL_DEPTH_BUFFER_BIT); //grab assets required to render window Model planeModel = Globals.assetManager.fetchModel(Globals.imagePlaneModelID); - Texture windowFrame = Globals.assetManager.fetchTexture("Textures/ui/uiFrame1.png"); + Texture windowFrame = Globals.assetManager.fetchTexture(AssetDataStrings.UI_FRAME_TEXTURE_DEFAULT_1); for(Element child : childList){ if(child instanceof DrawableElement){ @@ -227,7 +256,7 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme planeModel.pushUniformToMesh("plane", "mDimension", boxDimensions); planeModel.pushUniformToMesh("plane", "tPosition", texPosition); planeModel.pushUniformToMesh("plane", "tDimension", texScale); - planeModel.pushUniformToMesh(planeModel.getMeshes().get(0).getMeshName(), "color", color); + planeModel.pushUniformToMesh(planeModel.getMeshes().get(0).getMeshName(), "color", new Vector3f(1.0f)); customMat.setTexturePointer(widgetBuffer.getTexture().getTexturePointer()); planeModel.getMeshes().get(0).setMaterial(customMat); planeModel.drawUI(); @@ -239,7 +268,7 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme */ public void destroy(){ this.yogaNode = Element.NULL_YOGA_ELEMENT; - for(Element el : getChildren()){ + for(Element el : this.getChildren()){ Globals.signalSystem.post(SignalType.YOGA_DESTROY, el); } this.clearChildren(); @@ -252,7 +281,7 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme * clears all children */ public void clear(){ - for(Element el : getChildren()){ + for(Element el : this.getChildren()){ Globals.signalSystem.post(SignalType.YOGA_DESTROY, el); } this.clearChildren(); @@ -836,4 +865,38 @@ public class Window implements DrawableElement, ContainerElement, NavigableEleme Yoga.YGNodeStyleSetPadding(this.yogaNode, Yoga.YGEdgeLeft, paddingLeft); } + /** + * Gets the frame decoration texture path + * @return The frame decoration texture path + */ + public String getFrameDecoration() { + return frameDecoration; + } + + /** + * Sets the frame decoration texture path + * @param frameDecoration The frame decoration texture path + */ + public void setFrameDecoration(String frameDecoration) { + this.frameDecoration = frameDecoration; + } + + /** + * Gets the color of the window decorations + * @return The color of the decorations + */ + public Vector3f getColor() { + return color; + } + + /** + * Sets the color of the window decorations + * @param color The color of the decorations + */ + public void setColor(Vector3f color) { + this.color = color; + } + + + } diff --git a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java index e16e0b35..1b7b9ffe 100644 --- a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java @@ -19,7 +19,6 @@ import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.state.server.ServerPlayerViewDirTree; -import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.game.server.world.ServerWorldData; import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.EntityMessage; @@ -384,27 +383,36 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager } } for(ServerDataCell cell : toCleanQueue){ + boolean containsPlayerEntity = false; + //clear all entities in cell + for(Entity entity : cell.getScene().getEntityList()){ + if(ServerPlayerViewDirTree.hasTree(entity)){ + containsPlayerEntity = true; + break; + // int playerId = CreatureUtils.getControllerPlayerId(entity); + // Player player = Globals.playerManager.getPlayerFromId(playerId); + // throw new Error( + // "Trying to unload a player's entity! " + + // "entity: " + entity + "\n" + + // "entity pos (real): " + EntityUtils.getPosition(entity) + "\n" + + // "entity pos (world): " + serverWorldData.convertRealToWorldSpace(EntityUtils.getPosition(entity)) + "\n" + + // "chunk pos (world): " + worldPos + "\n" + + // "player pos (world): " + player.getWorldPos() + "\n" + + // "Number of players in cell: " + cell.getPlayers().size() + // ); + } + // ServerEntityUtils.destroyEntity(entity); + } + if(containsPlayerEntity){ + continue; + } parent.deregisterCell(cell); Vector3i worldPos = getCellWorldPosition(cell); Long key = getServerDataCellKey(worldPos); groundDataCells.remove(key); //offload all entities in cell to chunk file serverContentManager.saveContentToDisk(key, cell.getScene().getEntityList()); - //clear all entities in cell for(Entity entity : cell.getScene().getEntityList()){ - if(ServerPlayerViewDirTree.hasTree(entity)){ - int playerId = CreatureUtils.getControllerPlayerId(entity); - Player player = Globals.playerManager.getPlayerFromId(playerId); - throw new Error( - "Trying to unload a player's entity! " + - "entity: " + entity + "\n" + - "entity pos (real): " + EntityUtils.getPosition(entity) + "\n" + - "entity pos (world): " + serverWorldData.convertRealToWorldSpace(EntityUtils.getPosition(entity)) + "\n" + - "chunk pos (world): " + worldPos + "\n" + - "player pos (world): " + player.getWorldPos() + "\n" + - "Number of players in cell: " + cell.getPlayers().size() - ); - } ServerEntityUtils.destroyEntity(entity); } //save terrain to disk diff --git a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java index 5f4182e8..0149d06f 100644 --- a/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java +++ b/src/main/java/electrosphere/server/terrain/generation/TestGenerationChunkGenerator.java @@ -21,6 +21,7 @@ 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.MountainVoxelGen; import electrosphere.server.terrain.generation.voxelphase.VoxelGenerator; import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.models.TerrainModel; @@ -91,6 +92,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { this.registerHeightmapGenerator(new MountainGen()); this.registerVoxelGenerator(new HillsVoxelGen()); this.registerVoxelGenerator(new AnimeMountainsGen()); + this.registerVoxelGenerator(new MountainVoxelGen()); this.useJavascript = useJavascript; } @@ -123,7 +125,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { BiomeSurfaceGenerationParams surfaceParams = surfaceBiome.getSurfaceGenerationParams(); HeightmapGenerator heightmapGen = this.tagHeightmapMap.get(surfaceParams.getSurfaceGenTag()); - heightmapGen = this.tagHeightmapMap.get("mountains"); + heightmapGen = this.tagHeightmapMap.get("hills"); if(heightmapGen == null){ throw new Error("Undefined heightmap generator in biome! " + surfaceBiome.getId() + " " + surfaceBiome.getDisplayName() + " " + surfaceParams.getSurfaceGenTag()); } @@ -147,6 +149,25 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { } } + float[][] gradientField = 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++){ + float deltaX = 0; + float deltaZ = 0; + if(x < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 1){ + deltaX = Math.abs(heightfield[x][z] - heightfield[x+1][z]); + } else { + deltaX = Math.abs(heightfield[x][z] - heightfield[x-1][z]); + } + if(z < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE - 1){ + deltaX = Math.abs(heightfield[x][z] - heightfield[x][z+1]); + } else { + deltaX = Math.abs(heightfield[x][z] - heightfield[x][z-1]); + } + gradientField[x][z] = deltaX * deltaX + deltaZ * deltaZ; + } + } + VoxelGenerator voxelGenerator = this.tagVoxelMap.get("hills"); if(this.useJavascript){ @@ -212,7 +233,7 @@ public class TestGenerationChunkGenerator implements ChunkGenerator { finalWorldX, finalWorldY, finalWorldZ, finalChunkX, finalChunkY, finalChunkZ, stride, - heightfield[x][z], + heightfield[x][z], gradientField[x][z], surfaceBiome, generationContext ); diff --git a/src/main/java/electrosphere/server/terrain/generation/heightmap/MountainGen.java b/src/main/java/electrosphere/server/terrain/generation/heightmap/MountainGen.java index 667c58cd..398fb411 100644 --- a/src/main/java/electrosphere/server/terrain/generation/heightmap/MountainGen.java +++ b/src/main/java/electrosphere/server/terrain/generation/heightmap/MountainGen.java @@ -1,5 +1,6 @@ package electrosphere.server.terrain.generation.heightmap; +import electrosphere.util.noise.OpenSimplex2S; import io.github.studiorailgun.NoiseUtils; public class MountainGen implements HeightmapGenerator { @@ -17,18 +18,20 @@ public class MountainGen implements HeightmapGenerator { /** * Vertical scale of the noise */ - static final float VERTICAL_SCALE = 1024.0f; + static final float VERTICAL_SCALE = 512.0f; /** * Horizontal scale of the noise */ - static final float HORIZONTAL_SCALE = 1024.0f; + static final float HORIZONTAL_SCALE = 512.0f; /** * The power applied to the noise */ static final float POWER_SCALE = 2; + static final float RELAXATION_FACTOR = 0.13f; + /** * The scale to apply to the coordinates */ @@ -52,15 +55,40 @@ public class MountainGen implements HeightmapGenerator { * @return The height */ public float getHeight(long SEED, double x, double y){ + return this.getHeight1(SEED, x, y); + } + + /** + * Gets the height at a given position for this generation approach + * @param SEED The seed + * @param x The x position + * @param y The y position + * @return The height + */ + public float getHeight1(long SEED, double x, double y){ float rVal = 0.0f; double smoothVoronoiSample = NoiseUtils.smoothVoronoi(x * GEN_SCALE, y * GEN_SCALE, (double)SEED, FALLOFF_FACTOR); double inverted = 1.0 - smoothVoronoiSample; - double minClamped = Math.max(inverted,0.0f); + double noisy = inverted + + 0.02 * OpenSimplex2S.noise2(SEED, x * GEN_SCALE * 3, y * GEN_SCALE * 3) + + 0.005 * OpenSimplex2S.noise2(SEED, x * GEN_SCALE * 5, y * GEN_SCALE * 5) + ; + double minClamped = Math.max(noisy,0.0f); double powered = Math.pow(minClamped,POWER_SCALE); rVal = (float)powered * VERTICAL_SCALE; return rVal; } + public float getHeight2(long SEED, double x, double y){ + double invertedMinDist = ( + 1.0 * (NoiseUtils.voronoiRelaxed(x * GEN_SCALE, y * GEN_SCALE, RELAXATION_FACTOR)) + + 0.5 * (NoiseUtils.voronoiRelaxed(x * 1.2 * GEN_SCALE, y * 1.2 * GEN_SCALE, RELAXATION_FACTOR)) + + 0.3 * (NoiseUtils.voronoiRelaxed(x * 2 * GEN_SCALE, y * 2 * GEN_SCALE, RELAXATION_FACTOR)) + ); + + return (float)(Math.max(invertedMinDist - 0.6,0) / 1.6 * VERTICAL_SCALE); + } + @Override public String getTag() { 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 fb29ddd2..a6f306a2 100644 --- a/src/main/java/electrosphere/server/terrain/generation/voxelphase/AnimeMountainsGen.java +++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/AnimeMountainsGen.java @@ -67,7 +67,7 @@ public class AnimeMountainsGen implements VoxelGenerator { GeneratedVoxel voxel, int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, - int stride, float surfaceHeight, + int stride, float surfaceHeight, float surfaceGradient, BiomeData surfaceBiome, GenerationContext generationContext ) { 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 c6d9b0a3..59e73d54 100644 --- a/src/main/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGen.java +++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/HillsVoxelGen.java @@ -27,7 +27,7 @@ public class HillsVoxelGen implements VoxelGenerator { int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, int stride, - float surfaceHeight, + float surfaceHeight, float surfaceGradient, BiomeData surfaceBiome, GenerationContext generationContext ){ diff --git a/src/main/java/electrosphere/server/terrain/generation/voxelphase/MountainVoxelGen.java b/src/main/java/electrosphere/server/terrain/generation/voxelphase/MountainVoxelGen.java new file mode 100644 index 00000000..d79d0d82 --- /dev/null +++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/MountainVoxelGen.java @@ -0,0 +1,158 @@ +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; + +public class MountainVoxelGen implements VoxelGenerator { + + /** + * The width of the surface in number of voxels + */ + public static final int SURFACE_VOXEL_WIDTH = 2; + + /** + * Cutoff after which snow is placed + */ + public static final int SNOW_CUTOFF = 150; + + /** + * Gradient cutoff after which dirt is placed + */ + public static final float GRADIENT_DIRT_CUTOFF = 0.1f; + + + @Override + public String getTag(){ + return "mountains"; + } + + @Override + public void getVoxel( + GeneratedVoxel voxel, + int worldX, int worldY, int worldZ, + int chunkX, int chunkY, int chunkZ, + int stride, + float surfaceHeight, float surfaceGradient, + 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, surfaceGradient, + surfaceBiome + ); + } else if(heightDiff > 0) { + this.getOverSurfaceVoxel( + voxel, + worldX, worldY, worldZ, + chunkX, chunkY, chunkZ, + realX, realY, realZ,- + surfacePercent, + surfaceHeight, surfaceGradient, + surfaceBiome + ); + } else { + this.getSurfaceVoxel( + voxel, + worldX, worldY, worldZ, + chunkX, chunkY, chunkZ, + realX, realY, realZ, + surfacePercent, + surfaceHeight, surfaceGradient, + 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, float surfaceGradient, + BiomeData surfaceBiome + ){ + voxel.weight = (float)surfacePercent * 2 - 1; + voxel.type = 2; + if(realY > SNOW_CUTOFF){ + voxel.type = 5; + } else { + if(surfaceGradient > GRADIENT_DIRT_CUTOFF){ + voxel.type = 1; + } + } + } + + /** + * 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, float surfaceGradient, + 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, float surfaceGradient, + 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 index c0030c5b..af17ede9 100644 --- a/src/main/java/electrosphere/server/terrain/generation/voxelphase/VoxelGenerator.java +++ b/src/main/java/electrosphere/server/terrain/generation/voxelphase/VoxelGenerator.java @@ -29,6 +29,7 @@ public interface VoxelGenerator { * @param chunkZ The chunk z pos * @param stride The stride of the data * @param surfaceHeight The height of the surface at x,z + * @param surfaceGradient The rate of change in the surface at this point * @param surfaceBiome The surface biome of the chunk * @param generationContext The generation context */ @@ -37,7 +38,7 @@ public interface VoxelGenerator { int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, int stride, - float surfaceHeight, + float surfaceHeight, float surfaceGradient, BiomeData surfaceBiome, GenerationContext generationContext );