terrain generation testing realm
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2024-10-23 13:07:08 -04:00
parent d10da49140
commit aa70f39eb9
15 changed files with 501 additions and 15 deletions

1
.gitignore vendored
View File

@ -34,6 +34,7 @@
#saves
/saves/random_sp_world
/saves/defaultLevel*
/saves/generation_testing
#screenshots
/assets/Screenshots

View File

@ -12,6 +12,17 @@
"SPAWNPOINT"
]
},
{
"id" : "marker",
"graphicsTemplate": {
"model": {
"path" : "Models/gameobj/token.glb"
}
},
"tokens": [
"MARKER"
]
},
{
"id" : "flameEmitterTest",
"particleEmitter": {

View File

@ -13,8 +13,6 @@
- Old sword item
- Switch that requires being hit
- Door that can be locked
+ Lock third room behind climbing
- Climbing
+ Portal to tutorial hub area
- Portals
- Switching realms
@ -23,7 +21,6 @@
+ rearchitecture
+ fix the vibes
Tooltips for items, hover over with cursor, etc
Ticketed randomizer node for BTs to more heavily weight attacking and waiting
+ non-feedback requirements

View File

@ -897,6 +897,7 @@ Initial implementation of tooltips
(10/23/2024)
Tooltip improvements
Terrain generation testing realm
@ -961,6 +962,16 @@ Startup Performance
- Proactively send chunks on player loading in (ie, send all chunks that are all air before its even requested)
- Also send all 'dirt' or 'stone' chunks
Scripting enhancements
- setTimeout
- Get marker by entity name/id
- Play/Stop animations on actors
- Apply cameras
- Show/Hide UI
- Enable/disable controls states
- Spawn/Destroy entities
- Ability to define regions in space (ie with entities)
Code Generation
- Generate static "hasXComponent", "getXComponent" functions on sync'd components
@ -977,7 +988,6 @@ Code cleanup
- Rename "ShaderProgram" to "VisualShader"
- Have ComputeShader and VisualShader use same static method for uploading uniforms
Goof off today requirements:
Transvoxel implementation
- Fix draw cell manager requesting far-out chunks
- Properly update to higher LOD meshes as you get closer

View File

@ -63,6 +63,14 @@ public class MenuGeneratorsTitleMenu {
Globals.threadManager.start(loadingThread);
}).setOnClickAudio(AssetDataStrings.UI_TONE_BUTTON_TITLE));
//button (sp debug)
rVal.addChild(Button.createButtonCentered("Load Test Generation Realm", () -> {
LoadingThread loadingThread = new LoadingThread(LoadingThreadType.CHUNK_GENERATION_REALM);
Globals.RUN_CLIENT = true;
Globals.RUN_SERVER = true;
Globals.threadManager.start(loadingThread);
}).setOnClickAudio(AssetDataStrings.UI_TONE_BUTTON_TITLE));
//button (ui testing)
rVal.addChild(Button.createButtonCentered("UI Testing", () -> {
WindowUtils.replaceMainMenuContents(MenuGeneratorsUITesting.createUITestMenu());

View File

@ -0,0 +1,104 @@
package electrosphere.engine.loadingthreads;
import java.util.concurrent.TimeUnit;
import electrosphere.auth.AuthenticationManager;
import electrosphere.client.ui.menu.MenuGenerators;
import electrosphere.client.ui.menu.WindowStrings;
import electrosphere.client.ui.menu.WindowUtils;
import electrosphere.engine.Globals;
import electrosphere.engine.signal.Signal.SignalType;
import electrosphere.entity.scene.SceneGenerator;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.renderer.ui.elements.Window;
import electrosphere.server.saves.SaveUtils;
/**
* Loads the chunk generation testing realm
*/
public class ChunkGenerationTestLoading {
/**
* Loads the level editor
*/
protected static void loadChunkGenerationTesting(Object[] params){
//
//Set params we would expect to run with this thread
//
Globals.RUN_CLIENT = true;
Globals.RUN_SERVER = true;
Globals.RUN_PHYSICS = false;
Globals.aiManager.setActive(false);
Globals.signalSystem.post(SignalType.UI_MODIFICATION, ()->{
Window loadingWindow = (Window)Globals.elementService.getWindow(WindowStrings.WINDOW_LOADING);
//show loading
WindowUtils.recursiveSetVisible(Globals.elementService.getWindow(WindowStrings.WINDOW_MENU_MAIN), false);
WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu());
loadingWindow.setVisible(true);
});
String saveName = "generation_testing";
if(!SaveUtils.getSaves().contains(saveName)){
//
//the juicy server GENERATION part
//
//init save structure
SaveUtils.createOrOverwriteSave(saveName, SceneGenerator.createGenerationTestingSceneFile(saveName));
}
//load just-created save
SaveUtils.loadSave(saveName, false);
//initialize the "virtual" objects simulation
LoadingUtils.initMacroSimulation();
LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT);
//init authentication
LoadingUtils.initAuthenticationManager(false);
//initialize the local connection
Globals.clientUsername = "leveleditor";
Globals.clientPassword = AuthenticationManager.getHashedString("leveleditor");
ServerConnectionHandler serverPlayerConnection = LoadingUtils.initLocalConnection(true);
//wait for player object creation
while(Globals.playerManager.getPlayers().size() < 1 || !Globals.clientConnection.isInitialized()){
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//initialize the "real" objects simulation
LoadingUtils.initMicroSimulation();
//init game specific stuff (ie different skybox colors)
LoadingUtils.initGameGraphicalEntities();
//set simulations to ready if they exist
LoadingUtils.setSimulationsToReady();
//log
LoggerInterface.loggerEngine.INFO("[Server]Finished loading level editor");
//the less juicy client setup part
while(Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces().size() == 0){
try {
TimeUnit.MILLISECONDS.sleep(1);
} catch (InterruptedException ex) {}
}
//spawn player character
LoadingUtils.spawnLocalPlayerTestEntity(serverPlayerConnection, true);
//request terrain data
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestMetadataMessage());
//Run client startup process
ClientLoading.loadClientWorld(params);
}
}

View File

@ -40,6 +40,11 @@ public class LoadingThread extends Thread {
*/
DEBUG_RANDOM_SP_WORLD,
/**
* Loads a chunk generation testing realm
*/
CHUNK_GENERATION_REALM,
/**
* Loads the level editor
*/
@ -133,6 +138,11 @@ public class LoadingThread extends Thread {
DebugSPWorldLoading.loadDebugSPWorld(params);
} break;
//Loads a realm used for chunk generation testing
case CHUNK_GENERATION_REALM: {
ChunkGenerationTestLoading.loadChunkGenerationTesting(params);
} break;
//loads the level editor
case LEVEL_EDITOR: {
LevelEditorLoading.loadLevelEditor(params);

View File

@ -10,6 +10,7 @@ public class RealmDescriptor {
*/
public static final String REALM_DESCRIPTOR_GRIDDED = "gridded";
public static final String REALM_DESCRIPTOR_PROCEDURAL = "procedural";
public static final String REALM_DESCRIPTOR_GENERATION_TESTING = "generationTesting";
/**
* The dirt voxel type's id

View File

@ -1,6 +1,7 @@
package electrosphere.entity.scene;
import electrosphere.server.datacell.GriddedDataCellManager;
import electrosphere.server.terrain.generation.TestGenerationChunkGenerator;
/**
* Generates scene files where appropriate (ie, if playing the procedurally generated level)
@ -24,4 +25,21 @@ public class SceneGenerator {
return file;
}
/**
* Creates a scene file for the generation testing realm
* @param gridSize The size of the terrain grid of the scene
* @return The scene file
*/
public static SceneFile createGenerationTestingSceneFile(String saveName){
//base file stuff
SceneFile file = SceneFile.createSceneFile();
//realm descriptor stuff
file.realmDescriptor.type = RealmDescriptor.REALM_DESCRIPTOR_GENERATION_TESTING;
file.realmDescriptor.griddedRealmSize = TestGenerationChunkGenerator.GENERATOR_REALM_SIZE;
file.createSaveInstance = true; //won't have a predefined scene to load, so must create one in the save
file.loadAllCells = false; // do not load all cells on init
return file;
}
}

View File

@ -22,7 +22,9 @@ public class SceneLoader {
/**
* Loads a scene file on the server
* @param path The name of the save to look for a scene file within
* @param saveName The name of the save
* @param serverWorldData the server world data
* @param isLevelEditor true if this is a level editor, false otherwise
*/
public static void serverInstantiateSaveSceneFile(String saveName, ServerWorldData serverWorldData, boolean isLevelEditor){
//load scene file
@ -33,7 +35,9 @@ public class SceneLoader {
/**
* Loads a scene file on the server
* @param path The name of the scene in the assets/scenes folder
* @param sceneName The name of the scene
* @param serverWorldData the server world data
* @param isLevelEditor true if this is a level editor, false otherwise
*/
public static void serverInstantiateAssetSceneFile(String sceneName, ServerWorldData serverWorldData, boolean isLevelEditor){
//load scene file
@ -80,6 +84,10 @@ public class SceneLoader {
case RealmDescriptor.REALM_DESCRIPTOR_PROCEDURAL: {
realm = Globals.realmManager.createGriddedRealm(serverWorldData,serverContentManager);
} break;
case RealmDescriptor.REALM_DESCRIPTOR_GENERATION_TESTING: {
ServerWorldData newWorldData = ServerWorldData.createGenerationTestWorldData();
realm = Globals.realmManager.createGriddedRealm(newWorldData, serverContentManager);
} break;
default: {
throw new Error("Unhandled case! " + file.realmDescriptor.getType());
}

View File

@ -3,6 +3,7 @@ package electrosphere.game.server.world;
import electrosphere.server.fluid.generation.DefaultFluidGenerator;
import electrosphere.server.fluid.manager.ServerFluidManager;
import electrosphere.server.terrain.generation.DefaultChunkGenerator;
import electrosphere.server.terrain.generation.TestGenerationChunkGenerator;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.manager.ServerTerrainManager;
import electrosphere.util.FileUtils;
@ -133,6 +134,27 @@ public class ServerWorldData {
serverWorldData.setManagers(serverTerrainManager, serverFluidManager);
return serverWorldData;
}
/**
* Creates world data for testing generation
* @return The server world data
*/
public static ServerWorldData createGenerationTestWorldData(){
//
//Read world data if it exists
//
ServerWorldData serverWorldData = null;
ServerTerrainManager serverTerrainManager = null;
ServerFluidManager serverFluidManager = null;
//TODO: Allow loading procedurally generated terrain from disk (the chunk generator is always default currently)
serverWorldData = ServerWorldData.createFixedWorldData(new Vector3d(0),new Vector3d(16 * 4 * 4));
serverWorldData.worldSizeDiscrete = TestGenerationChunkGenerator.GENERATOR_REALM_SIZE;
serverWorldData.worldSizeDiscreteVertical = TestGenerationChunkGenerator.GENERATOR_REALM_SIZE;
serverTerrainManager = new ServerTerrainManager(serverWorldData, 0, new TestGenerationChunkGenerator());
serverFluidManager = new ServerFluidManager(serverWorldData, serverTerrainManager, 0, new DefaultFluidGenerator());
serverWorldData.setManagers(serverTerrainManager, serverFluidManager);
return serverWorldData;
}
public Vector3f getWorldBoundMin(){

View File

@ -13,12 +13,20 @@ import java.util.Properties;
*/
public class DatabaseController {
/**
* The database connection
*/
Connection conn;
public DatabaseController(){
}
/**
* Constructor
*/
public DatabaseController(){ }
/**
* Connects to a database
* @param path The path to the database
*/
public void connect(String path){
String dbms = "sqlite";
Properties connectionProps = new Properties();
@ -107,6 +115,10 @@ public class DatabaseController {
return rVal;
}
/**
* Checks of the connection is actually connected
* @return true if connected, false otherwise
*/
public boolean isConnected(){
boolean rVal = false;
if(conn == null){
@ -120,6 +132,9 @@ public class DatabaseController {
return rVal;
}
/**
* Disconnects from the database
*/
public void disconnect(){
try {
conn.close();

View File

@ -0,0 +1,104 @@
package electrosphere.server.terrain.generation;
import java.util.Arrays;
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.models.TerrainModel;
/**
* A generator for testing terrain generation
*/
public class TestGenerationChunkGenerator implements ChunkGenerator {
/**
* The size of the realm for testing generation
*/
public static final int GENERATOR_REALM_SIZE = 10;
/**
* The terreain model for the generator
*/
TerrainModel terrainModel;
@Override
public ServerTerrainChunk generateChunk(int worldX, int worldY, int worldZ) {
ServerTerrainChunk rVal = null;
float[][][] weights;
int[][][] values;
if(worldX == 0 || worldZ == 0){
//generate flat ground for the player to spawn on
weights = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
Arrays.fill(weights[x][y],-1f);
}
}
if(worldY == 0){
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
values[x][0][z] = 1;
weights[x][0][z] = 0.1f;
}
}
}
} else {
//actual generation algo
weights = new float[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
values = new int[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION; x++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
for(int z = 0; z < ServerTerrainChunk.CHUNK_DIMENSION; z++){
weights[x][y][z] = this.getChunkWeight(worldX, worldY, worldZ, x, y, z, this.terrainModel);
values[x][y][z] = this.getChunkValue(worldX, worldY, worldZ, x, y, z, this.terrainModel);
}
}
}
}
rVal = new ServerTerrainChunk(worldX, worldY, worldZ, weights, values);
return rVal;
}
@Override
public void setModel(TerrainModel model) {
this.terrainModel = model;
}
/**
* Gets the value for a chunk
* @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 terrainModel The terrain model
* @return The value of the chunk
*/
private int getChunkValue(int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, TerrainModel terrainModel){
return 1;
}
/**
* Gets the weight for a chunk
* @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 terrainModel The terrain model
* @return The weight of the chunk
*/
private float getChunkWeight(int worldX, int worldY, int worldZ, int chunkX, int chunkY, int chunkZ, TerrainModel terrainModel){
return 0.1f;
}
}

View File

@ -12,16 +12,54 @@ import electrosphere.server.terrain.models.TerrainModification;
*/
public class ServerTerrainChunk {
//all chunks are 16x16x16
/**
* All chunks are 16x16x16
*/
public static final int CHUNK_DIMENSION = 16;
//The size of the data passed into marching cubes/transvoxel to generate a fully connected and seamless chunk
/**
* The size of the data passed into marching cubes/transvoxel to generate a fully connected and seamless chunk
*/
public static final int CHUNK_DATA_GENERATOR_SIZE = CHUNK_DIMENSION + 1;
int worldX, worldY, worldZ;
/**
* Gets the x coordinate of the world position of the chunk
*/
int worldX;
/**
* Gets the y coordinate of the world position of the chunk
*/
int worldY;
/**
* Gets the z coordinate of the world position of the chunk
*/
int worldZ;
/**
* The list of modifications applied to the chunk
*/
List<TerrainModification> modifications = new LinkedList<TerrainModification>();
/**
* The weights of the chunk
*/
float[][][] weights;
/**
* The values of the chunk
*/
int[][][] values;
/**
* Constructor
* @param worldX The world position x coordinate
* @param worldY The world position y coordinate
* @param worldZ The world position z coordinate
* @param weights The weights of the chunk
* @param values The values of the chunk
*/
public ServerTerrainChunk(int worldX, int worldY, int worldZ, float[][][] weights, int[][][] values) {
this.worldX = worldX;
this.worldY = worldY;
@ -30,18 +68,38 @@ public class ServerTerrainChunk {
this.values = values;
}
/**
* Gets the world position x coordinate
* @return The x coordinate
*/
public int getWorldX() {
return worldX;
}
/**
* Gets the world position y coordinate
* @return The y coordinate
*/
public int getWorldY() {
return worldY;
}
/**
* Gets the world position z coordinate
* @return The z coordinate
*/
public int getWorldZ() {
return worldZ;
}
/**
* Gets the world position of the chunk
* @return The world position
*/
public Vector3i getWorldPos(){
return new Vector3i(worldX,worldY,worldZ);
}
/**
* Gets the world position of this terrain chunk as a joml Vector
* @return The vector
@ -50,18 +108,34 @@ public class ServerTerrainChunk {
return new Vector3i(worldX,worldY,worldZ);
}
/**
* Gets the list of all modifications applied to the chunk
* @return THe list of all modifications
*/
public List<TerrainModification> getModifications() {
return modifications;
}
/**
* Gets the weights of the chunk
* @return The weights of the chunk
*/
public float[][][] getWeights() {
return weights;
}
/**
* Gets the values of the chunk
* @return The values of the chunk
*/
public int[][][] getValues() {
return values;
}
/**
* Adds a modification to the chunk
* @param modification The modification
*/
public void addModification(TerrainModification modification){
modifications.add(modification);
values[modification.getVoxelPos().x][modification.getVoxelPos().y][modification.getVoxelPos().z] = modification.getValue();

View File

@ -5,25 +5,63 @@ import java.util.Map;
import electrosphere.util.annotation.Exclude;
/**
* The model of the terrain
*/
public class TerrainModel {
/**
* The dynamic interpolation ratio
*/
int dynamicInterpolationRatio;
/**
* The interpolation dampener
*/
float interpolationRandomDampener = 0.4f;
/**
* The discrete array dimension of the model
*/
int discreteArrayDimension;
/**
* The macro level elevation data
*/
@Exclude
private float[][] elevation;
/**
* The real coordinate mountain threshold
*/
float realMountainThreshold;
/**
* The real coordinate ocean threshold
*/
float realOceanThreshold;
/**
* The map of modifications applied to the model
*/
Map<String,ModificationList> modifications;
/**
* Private constructor
*/
TerrainModel() {
this.modifications = new HashMap<String,ModificationList>();
}
/**
* Constructor
* @param dimension The dimension of the model
* @param elevation The macro elevation data
* @param realOceanThreshold The real coordinate ocean threshold
* @param realMountainThreshold The real coordinate mountain threshold
* @param dynamicInterpolationRatio The dynamic interpolation ratio
*/
public TerrainModel(
int dimension,
float[][] elevation,
@ -40,6 +78,12 @@ public class TerrainModel {
this.modifications = new HashMap<String,ModificationList>();
}
/**
* Constructs a terrain model
* @param dimension The dimension of the terrain model
* @param dynamicInterpolationRatio The dynamic interpolation ratio
* @return The terrain model
*/
public static TerrainModel constructTerrainModel(int dimension, int dynamicInterpolationRatio){
TerrainModel rVal = new TerrainModel();
rVal.discreteArrayDimension = dimension;
@ -47,10 +91,18 @@ public class TerrainModel {
return rVal;
}
/**
* Gets the macro elevation data for the terrain model
* @return The macro elevation data
*/
public float[][] getElevation(){
return elevation;
}
/**
* Gets the interpolation random dampener
* @param f The interpolation random dampener
*/
public void setInterpolationRandomDampener(float f){
interpolationRandomDampener = f;
}
@ -205,6 +257,12 @@ public class TerrainModel {
*/
/**
* Gets the macro values at a position
* @param x The world x position
* @param y The world y position
* @return The macro values
*/
public float[][] getMacroValuesAtPosition(int x, int y){
float[][] rVal = new float[3][3];
@ -260,7 +318,12 @@ public class TerrainModel {
/**
* Gets the 5-radius macro values at a position
* @param x The x position
* @param y The y position
* @return The macro values
*/
public float[][] getRad5MacroValuesAtPosition(int x, int y){
float[][] rVal = new float[5][5];
@ -305,26 +368,53 @@ public class TerrainModel {
*/
/**
* Gets the random dampener for the model
* @return The random dampener
*/
public float getRandomDampener(){
return interpolationRandomDampener;
}
/**
* Gets the dynamic interpolation ratio
* @return The ratio
*/
public int getDynamicInterpolationRatio(){
return dynamicInterpolationRatio;
}
/**
* Gets the real coordinate mountain threshold
* @return The threshold
*/
public float getRealMountainThreshold() {
return realMountainThreshold;
}
/**
* Gets the real coordinate ocean threshold
* @return The threshold
*/
public float getRealOceanThreshold() {
return realOceanThreshold;
}
/**
* Gets a modification key
* @param x The world x position
* @param y The world y position
* @param z The world z position
* @return The key
*/
public String getModificationKey(int x, int y, int z){
return x + "_" + y + "_" + z;
}
/**
* Adds a terrain modification to the model
* @param modification The modification
*/
public void addModification(TerrainModification modification){
String key = getModificationKey(modification.getWorldPos().x,modification.getWorldPos().y,modification.getWorldPos().z);
ModificationList list;
@ -337,12 +427,25 @@ public class TerrainModel {
list.addModification(modification);
}
/**
* Checks if a modification has been applied at a world position
* @param worldX The x coordinate of the world position
* @param worldY The y coordinate of the world position
* @param worldZ The z coordinate of the world position
* @return true if there is a modification, false otherwise
*/
public boolean containsModificationsAtCoord(int worldX, int worldY, int worldZ){
return modifications.containsKey(getModificationKey(worldX, worldY, worldZ));
}
/**
* Gets the terrain modification at the world position
* @param worldX The x coordinate of the world position
* @param worldY The y coordinate of the world position
* @param worldZ The z coordinate of the world position
* @return The modification if there is one at the position, null otherwise
*/
public ModificationList getModifications(int worldX, int worldY, int worldZ){
// System.out.println("Got modifications at " + worldX + " " + worldY);
return modifications.get(getModificationKey(worldX, worldY, worldZ));
}