diff --git a/docs/src/architecture/authentication/authentication.md b/docs/src/architecture/authentication/authentication.md new file mode 100644 index 00000000..5303915c --- /dev/null +++ b/docs/src/architecture/authentication/authentication.md @@ -0,0 +1,5 @@ +@page authentication Authentication + +TODO: how authentication works + +Look at DebugSPWorldLoading if you want to have a loading thread that preempts the auth system locally \ No newline at end of file diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index a860d6cb..7cdbd82d 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -146,6 +146,8 @@ Overhaul mesh class (03/10/2024) De-dupe render calls via doing mutations in render pipeline status and dont call setting variables to values they are already set to +Render pipeline updates to support multiple pipelines defined in different files + - Grouping meshes together independent of actor so don't have to rebind shader programs or VAOs to redraw (03/12/2024) Foliage Manager upgrades @@ -185,12 +187,23 @@ Physics-controlled objects system Clean up main method/class - Include Remotery library +(03/24/2024) +Bring LWJGL version up to latest -# TODO +Automatic Scene unloading + - Tree structure inside scenes for tearing down groups of entities + - Entity decomposition + - Server handling + - Client handling when scene should be unloaded Level loading/saving + Basic Editor - Spin up voxel level (think arena mode) - Save voxel level + + +# TODO + +Level loading/saving + Basic Editor - Basic editor functionality - Menu of types of entities to spawn - Button to spawn them at cursor @@ -310,8 +323,6 @@ Upgrade terrain editing user experience further - Lock to axis tools - Server validation for client request to change terrain -Bring LWJGL version up to latest - @@ -326,11 +337,6 @@ Upgrade terrain generation algorithms # Eventually -Automatic Scene unloading - - Tree structure inside scenes for tearing down groups of entities - - Entity decomposition - - Server handling - - Client handling when scene should be unloaded Generic collision engine to support different instances of engine (eg hitboxes vs terrain vs liquids, etc) - Major refactoring to happen here Procedural Cliff Texture @@ -338,8 +344,6 @@ Procedural Cliff Texture Terrain Chunks: - Scale textures to be 1 texture per unit of terrain - Texture atlasing (512x512) -Render pipeline updates to support multiple pipelines defined in different files - - Grouping meshes together independent of actor so don't have to rebind shader programs or VAOs to redraw Loot Generator - System that can generate items that would be appropriate reward given some variables - ie you tell it 'this is this character's stats, this is the relative level of loot I want to provide' diff --git a/saves/defaultLevel_0/0_0_0t.dat b/saves/defaultLevel_0/0_0_0t.dat new file mode 100644 index 00000000..40d281ea Binary files /dev/null and b/saves/defaultLevel_0/0_0_0t.dat differ diff --git a/saves/defaultLevel_0/0_0_1t.dat b/saves/defaultLevel_0/0_0_1t.dat new file mode 100644 index 00000000..40d281ea Binary files /dev/null and b/saves/defaultLevel_0/0_0_1t.dat differ diff --git a/saves/defaultLevel_0/0_0_2t.dat b/saves/defaultLevel_0/0_0_2t.dat new file mode 100644 index 00000000..40d281ea Binary files /dev/null and b/saves/defaultLevel_0/0_0_2t.dat differ diff --git a/saves/defaultLevel_0/0_1_0t.dat b/saves/defaultLevel_0/0_1_0t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/0_1_0t.dat differ diff --git a/saves/defaultLevel_0/0_1_1t.dat b/saves/defaultLevel_0/0_1_1t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/0_1_1t.dat differ diff --git a/saves/defaultLevel_0/0_1_2t.dat b/saves/defaultLevel_0/0_1_2t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/0_1_2t.dat differ diff --git a/saves/defaultLevel_0/0_2_0t.dat b/saves/defaultLevel_0/0_2_0t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/0_2_0t.dat differ diff --git a/saves/defaultLevel_0/0_2_1t.dat b/saves/defaultLevel_0/0_2_1t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/0_2_1t.dat differ diff --git a/saves/defaultLevel_0/0_2_2t.dat b/saves/defaultLevel_0/0_2_2t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/0_2_2t.dat differ diff --git a/saves/defaultLevel_0/1_0_0t.dat b/saves/defaultLevel_0/1_0_0t.dat new file mode 100644 index 00000000..40d281ea Binary files /dev/null and b/saves/defaultLevel_0/1_0_0t.dat differ diff --git a/saves/defaultLevel_0/1_0_1t.dat b/saves/defaultLevel_0/1_0_1t.dat new file mode 100644 index 00000000..40d281ea Binary files /dev/null and b/saves/defaultLevel_0/1_0_1t.dat differ diff --git a/saves/defaultLevel_0/1_0_2t.dat b/saves/defaultLevel_0/1_0_2t.dat new file mode 100644 index 00000000..40d281ea Binary files /dev/null and b/saves/defaultLevel_0/1_0_2t.dat differ diff --git a/saves/defaultLevel_0/1_1_0t.dat b/saves/defaultLevel_0/1_1_0t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/1_1_0t.dat differ diff --git a/saves/defaultLevel_0/1_1_1t.dat b/saves/defaultLevel_0/1_1_1t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/1_1_1t.dat differ diff --git a/saves/defaultLevel_0/1_1_2t.dat b/saves/defaultLevel_0/1_1_2t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/1_1_2t.dat differ diff --git a/saves/defaultLevel_0/1_2_0t.dat b/saves/defaultLevel_0/1_2_0t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/1_2_0t.dat differ diff --git a/saves/defaultLevel_0/1_2_1t.dat b/saves/defaultLevel_0/1_2_1t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/1_2_1t.dat differ diff --git a/saves/defaultLevel_0/1_2_2t.dat b/saves/defaultLevel_0/1_2_2t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/1_2_2t.dat differ diff --git a/saves/defaultLevel_0/2_0_0t.dat b/saves/defaultLevel_0/2_0_0t.dat new file mode 100644 index 00000000..40d281ea Binary files /dev/null and b/saves/defaultLevel_0/2_0_0t.dat differ diff --git a/saves/defaultLevel_0/2_0_1t.dat b/saves/defaultLevel_0/2_0_1t.dat new file mode 100644 index 00000000..40d281ea Binary files /dev/null and b/saves/defaultLevel_0/2_0_1t.dat differ diff --git a/saves/defaultLevel_0/2_0_2t.dat b/saves/defaultLevel_0/2_0_2t.dat new file mode 100644 index 00000000..40d281ea Binary files /dev/null and b/saves/defaultLevel_0/2_0_2t.dat differ diff --git a/saves/defaultLevel_0/2_1_0t.dat b/saves/defaultLevel_0/2_1_0t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/2_1_0t.dat differ diff --git a/saves/defaultLevel_0/2_1_1t.dat b/saves/defaultLevel_0/2_1_1t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/2_1_1t.dat differ diff --git a/saves/defaultLevel_0/2_1_2t.dat b/saves/defaultLevel_0/2_1_2t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/2_1_2t.dat differ diff --git a/saves/defaultLevel_0/2_2_0t.dat b/saves/defaultLevel_0/2_2_0t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/2_2_0t.dat differ diff --git a/saves/defaultLevel_0/2_2_1t.dat b/saves/defaultLevel_0/2_2_1t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/2_2_1t.dat differ diff --git a/saves/defaultLevel_0/2_2_2t.dat b/saves/defaultLevel_0/2_2_2t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/2_2_2t.dat differ diff --git a/saves/defaultLevel_0/3_1_1t.dat b/saves/defaultLevel_0/3_1_1t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/3_1_1t.dat differ diff --git a/saves/defaultLevel_0/3_1_2t.dat b/saves/defaultLevel_0/3_1_2t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/3_1_2t.dat differ diff --git a/saves/defaultLevel_0/3_2_1t.dat b/saves/defaultLevel_0/3_2_1t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/3_2_1t.dat differ diff --git a/saves/defaultLevel_0/3_2_2t.dat b/saves/defaultLevel_0/3_2_2t.dat new file mode 100644 index 00000000..41183a70 Binary files /dev/null and b/saves/defaultLevel_0/3_2_2t.dat differ diff --git a/saves/defaultLevel_0/central.db b/saves/defaultLevel_0/central.db new file mode 100644 index 00000000..5034033f Binary files /dev/null and b/saves/defaultLevel_0/central.db differ diff --git a/saves/defaultLevel_0/chunk.map b/saves/defaultLevel_0/chunk.map new file mode 100644 index 00000000..fc7ab7a1 --- /dev/null +++ b/saves/defaultLevel_0/chunk.map @@ -0,0 +1 @@ +{"2_0_0t":"2_0_0t.dat","0_2_1t":"0_2_1t.dat","0_1_2t":"0_1_2t.dat","3_1_2t":"3_1_2t.dat","3_2_1t":"3_2_1t.dat","1_2_2t":"1_2_2t.dat","1_2_0t":"1_2_0t.dat","1_1_0t":"1_1_0t.dat","1_0_1t":"1_0_1t.dat","1_1_1t":"1_1_1t.dat","1_0_2t":"1_0_2t.dat","2_2_1t":"2_2_1t.dat","0_0_0t":"0_0_0t.dat","2_1_2t":"2_1_2t.dat","0_0_2t":"0_0_2t.dat","2_1_0t":"2_1_0t.dat","2_0_1t":"2_0_1t.dat","0_2_0t":"0_2_0t.dat","0_1_1t":"0_1_1t.dat","3_2_2t":"3_2_2t.dat","3_1_1t":"3_1_1t.dat","0_2_2t":"0_2_2t.dat","1_2_1t":"1_2_1t.dat","1_0_0t":"1_0_0t.dat","1_1_2t":"1_1_2t.dat","2_2_2t":"2_2_2t.dat","2_1_1t":"2_1_1t.dat","2_0_2t":"2_0_2t.dat","0_1_0t":"0_1_0t.dat","2_2_0t":"2_2_0t.dat","0_0_1t":"0_0_1t.dat"} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/0_0_0.dat b/saves/defaultLevel_0/content/0_0_0.dat new file mode 100644 index 00000000..c551c21e --- /dev/null +++ b/saves/defaultLevel_0/content/0_0_0.dat @@ -0,0 +1 @@ +{"serializedEntities":[{"type":0,"subtype":"human","position":{"x":4.098125672683711,"y":0.08169226990033779,"z":5.468832591049587},"rotation":{"x":-0.0,"y":-0.9423499800340845,"z":0.0,"w":0.3346289215381131}}]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/0_0_1.dat b/saves/defaultLevel_0/content/0_0_1.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/0_0_1.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/0_0_2.dat b/saves/defaultLevel_0/content/0_0_2.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/0_0_2.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/0_1_0.dat b/saves/defaultLevel_0/content/0_1_0.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/0_1_0.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/0_1_1.dat b/saves/defaultLevel_0/content/0_1_1.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/0_1_1.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/0_1_2.dat b/saves/defaultLevel_0/content/0_1_2.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/0_1_2.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/0_2_0.dat b/saves/defaultLevel_0/content/0_2_0.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/0_2_0.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/0_2_1.dat b/saves/defaultLevel_0/content/0_2_1.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/0_2_1.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/0_2_2.dat b/saves/defaultLevel_0/content/0_2_2.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/0_2_2.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/1_0_0.dat b/saves/defaultLevel_0/content/1_0_0.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/1_0_0.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/1_0_1.dat b/saves/defaultLevel_0/content/1_0_1.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/1_0_1.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/1_0_2.dat b/saves/defaultLevel_0/content/1_0_2.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/1_0_2.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/1_1_0.dat b/saves/defaultLevel_0/content/1_1_0.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/1_1_0.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/1_1_1.dat b/saves/defaultLevel_0/content/1_1_1.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/1_1_1.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/1_1_2.dat b/saves/defaultLevel_0/content/1_1_2.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/1_1_2.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/1_2_0.dat b/saves/defaultLevel_0/content/1_2_0.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/1_2_0.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/1_2_1.dat b/saves/defaultLevel_0/content/1_2_1.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/1_2_1.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/1_2_2.dat b/saves/defaultLevel_0/content/1_2_2.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/1_2_2.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/2_0_0.dat b/saves/defaultLevel_0/content/2_0_0.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/2_0_0.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/2_0_1.dat b/saves/defaultLevel_0/content/2_0_1.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/2_0_1.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/2_0_2.dat b/saves/defaultLevel_0/content/2_0_2.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/2_0_2.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/2_1_0.dat b/saves/defaultLevel_0/content/2_1_0.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/2_1_0.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/2_1_1.dat b/saves/defaultLevel_0/content/2_1_1.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/2_1_1.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/2_1_2.dat b/saves/defaultLevel_0/content/2_1_2.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/2_1_2.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/2_2_0.dat b/saves/defaultLevel_0/content/2_2_0.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/2_2_0.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/2_2_1.dat b/saves/defaultLevel_0/content/2_2_1.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/2_2_1.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/content/2_2_2.dat b/saves/defaultLevel_0/content/2_2_2.dat new file mode 100644 index 00000000..8cdcf255 --- /dev/null +++ b/saves/defaultLevel_0/content/2_2_2.dat @@ -0,0 +1 @@ +{"serializedEntities":[]} \ No newline at end of file diff --git a/saves/defaultLevel_0/world.json b/saves/defaultLevel_0/world.json new file mode 100644 index 00000000..c9c48ba9 --- /dev/null +++ b/saves/defaultLevel_0/world.json @@ -0,0 +1 @@ +{"type":"GAME_WORLD","worldMinPoint":{"x":0.0,"y":0.0,"z":0.0},"worldMaxPoint":{"x":48.0,"y":0.0,"z":48.0},"worldSizeDiscrete":3,"worldSizeDiscreteVertical":128,"dynamicInterpolationRatio":0,"randomDampener":0.0,"isArena":false} \ No newline at end of file diff --git a/src/main/java/electrosphere/auth/AuthenticationManager.java b/src/main/java/electrosphere/auth/AuthenticationManager.java index 43df2ba8..9adc9b99 100644 --- a/src/main/java/electrosphere/auth/AuthenticationManager.java +++ b/src/main/java/electrosphere/auth/AuthenticationManager.java @@ -49,6 +49,10 @@ public class AuthenticationManager { public static String getHashedString(String input){ String rVal = ""; + if(input == "" || input == null){ + input = "asdf"; + } + //generate salt char[] charArray = input.toCharArray(); byte[] salt = new byte[saltLength]; diff --git a/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java index e11d9a0b..d5480c50 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java @@ -64,7 +64,7 @@ public class ArenaLoading { private static void initServerArenaWorldData(){ Globals.serverWorldData = ServerWorldData.createArenaWorld(); - Globals.serverContentManager = ServerContentManager.createServerContentManager(); + Globals.serverContentManager = ServerContentManager.createServerContentManager(false); Globals.spawnPoint = new Vector3d(1,0.1,1); // Globals.serverTerrainManager.getChunk(0, 0).addModification(new TerrainModification(0,0,5,5,5)); } diff --git a/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java b/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java index 0d8d6df9..ddd99896 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java @@ -37,29 +37,29 @@ public class DebugSPWorldLoading { Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0, new OverworldChunkGenerator()); Globals.currentSaveName = "random_sp_world"; - if(!SaveUtils.getSaves().contains("random_sp_world")){ + if(!SaveUtils.getSaves().contains(Globals.currentSaveName)){ // //the juicy server GENERATION part // //init save structure - SaveUtils.createOrOverwriteSave("random_sp_world"); + SaveUtils.createOrOverwriteSave(Globals.currentSaveName); //create terrain Globals.serverTerrainManager.generate(); - Globals.serverTerrainManager.save("random_sp_world"); + Globals.serverTerrainManager.save(Globals.currentSaveName); //create world.json Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); - FileUtils.serializeObjectToSavePath("random_sp_world", "./world.json", Globals.serverWorldData); + FileUtils.serializeObjectToSavePath(Globals.currentSaveName, "./world.json", Globals.serverWorldData); //create mock fluid sim manager Globals.serverFluidManager = new ServerFluidManager(Globals.serverTerrainManager, 2000, 50, 0.0f, 0, new ArenaFluidGenerator()); } //load just-created save - SaveUtils.loadSave("random_sp_world"); + SaveUtils.loadSave(Globals.currentSaveName); //start initializing game datastructures // Globals.griddedDataCellManager.init(Globals.serverWorldData); //initialize the "virtual" objects simulation LoadingUtils.initMacroSimulation(); - Globals.serverContentManager = ServerContentManager.createServerContentManager(); + Globals.serverContentManager = ServerContentManager.createServerContentManager(true); LoadingUtils.initGriddedRealm(); diff --git a/src/main/java/electrosphere/engine/loadingthreads/LevelEditorLoading.java b/src/main/java/electrosphere/engine/loadingthreads/LevelEditorLoading.java new file mode 100644 index 00000000..8b8a659b --- /dev/null +++ b/src/main/java/electrosphere/engine/loadingthreads/LevelEditorLoading.java @@ -0,0 +1,102 @@ +package electrosphere.engine.loadingthreads; + +import java.util.concurrent.TimeUnit; + +import electrosphere.auth.AuthenticationManager; +import electrosphere.engine.Globals; +import electrosphere.game.server.world.ServerWorldData; +import electrosphere.logger.LoggerInterface; +import electrosphere.menu.MenuGenerators; +import electrosphere.menu.WindowStrings; +import electrosphere.menu.WindowUtils; +import electrosphere.net.parser.net.message.TerrainMessage; +import electrosphere.net.server.ServerConnectionHandler; +import electrosphere.renderer.ui.Window; +import electrosphere.server.content.ServerContentManager; +import electrosphere.server.fluid.generation.ArenaFluidGenerator; +import electrosphere.server.fluid.manager.ServerFluidManager; +import electrosphere.server.saves.SaveUtils; +import electrosphere.server.terrain.generation.ArenaChunkGenerator; +import electrosphere.server.terrain.generation.OverworldChunkGenerator; +import electrosphere.server.terrain.manager.ServerTerrainManager; +import electrosphere.util.FileUtils; + +/** + * Loads the level editor + */ +public class LevelEditorLoading { + + /** + * Loads the level editor + */ + protected static void loadLevelEditor(){ + Window loadingWindow = (Window)Globals.elementManager.getWindow(WindowStrings.WINDOW_LOADING); + //show loading + WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), false); + WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); + loadingWindow.setVisible(true); + + Globals.serverTerrainManager = new ServerTerrainManager(3,1,0.0f,0, new ArenaChunkGenerator()); + if(!SaveUtils.getSaves().contains(Globals.currentSaveName)){ + //init save structure + SaveUtils.createOrOverwriteSave(Globals.currentSaveName); + //create world.json + Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); + FileUtils.serializeObjectToSavePath(Globals.currentSaveName, "./world.json", Globals.serverWorldData); + //create mock fluid sim manager + Globals.serverFluidManager = new ServerFluidManager(Globals.serverTerrainManager, 3, 1, 0.0f, 0, new ArenaFluidGenerator()); + //save terrain manager + Globals.serverTerrainManager.save(Globals.currentSaveName); + } + //load just-created save + SaveUtils.loadSave(Globals.currentSaveName); + + //init server content manager + Globals.serverContentManager = ServerContentManager.createServerContentManager(false); + + //creates a gridded realm + LoadingUtils.initGriddedRealm(); + + + LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT); + //init authentication + LoadingUtils.initAuthenticationManager(); + //initialize the local connection + Globals.clientUsername = "leveleditor"; + Globals.clientPassword = AuthenticationManager.getHashedString("leveleditor"); + ServerConnectionHandler serverPlayerConnection = LoadingUtils.initLocalConnection(); + //wait for player object creation + while(Globals.playerManager.getPlayers().size() < 1){ + try { + TimeUnit.MILLISECONDS.sleep(10); + } 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(5); + } catch (InterruptedException ex) {} + } + + //spawn player character + LoadingUtils.spawnLocalPlayerTestEntity(serverPlayerConnection); + + //request terrain data + Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestMetadataMessage()); + + //Run client startup process + ClientLoading.loadClientWorld(); + } + +} diff --git a/src/main/java/electrosphere/engine/loadingthreads/LevelLoading.java b/src/main/java/electrosphere/engine/loadingthreads/LevelLoading.java new file mode 100644 index 00000000..320e3efd --- /dev/null +++ b/src/main/java/electrosphere/engine/loadingthreads/LevelLoading.java @@ -0,0 +1,84 @@ +package electrosphere.engine.loadingthreads; + +import java.util.concurrent.TimeUnit; + +import electrosphere.auth.AuthenticationManager; +import electrosphere.engine.Globals; +import electrosphere.logger.LoggerInterface; +import electrosphere.menu.MenuGenerators; +import electrosphere.menu.WindowStrings; +import electrosphere.menu.WindowUtils; +import electrosphere.net.parser.net.message.TerrainMessage; +import electrosphere.net.server.ServerConnectionHandler; +import electrosphere.renderer.ui.Window; +import electrosphere.server.content.ServerContentManager; +import electrosphere.server.saves.SaveUtils; + +/** + * Loads a given level + */ +public class LevelLoading { + + /** + * Loads the level editor + */ + protected static void loadLevel(){ + Window loadingWindow = (Window)Globals.elementManager.getWindow(WindowStrings.WINDOW_LOADING); + //show loading + WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), false); + WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); + loadingWindow.setVisible(true); + + //load just-created save + SaveUtils.loadSave(Globals.currentSaveName); + + //init server content manager + Globals.serverContentManager = ServerContentManager.createServerContentManager(false); + + //creates a gridded realm + LoadingUtils.initGriddedRealm(); + + + LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT); + //init authentication + LoadingUtils.initAuthenticationManager(); + //initialize the local connection + Globals.clientUsername = "leveleditor"; + Globals.clientPassword = AuthenticationManager.getHashedString("leveleditor"); + ServerConnectionHandler serverPlayerConnection = LoadingUtils.initLocalConnection(); + //wait for player object creation + while(Globals.playerManager.getPlayers().size() < 1){ + try { + TimeUnit.MILLISECONDS.sleep(10); + } 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(5); + } catch (InterruptedException ex) {} + } + + //spawn player character + LoadingUtils.spawnLocalPlayerTestEntity(serverPlayerConnection); + + //request terrain data + Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestMetadataMessage()); + + //Run client startup process + ClientLoading.loadClientWorld(); + } + + +} diff --git a/src/main/java/electrosphere/engine/loadingthreads/LoadingThread.java b/src/main/java/electrosphere/engine/loadingthreads/LoadingThread.java index 3924906f..385d2a8f 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/LoadingThread.java +++ b/src/main/java/electrosphere/engine/loadingthreads/LoadingThread.java @@ -14,6 +14,8 @@ public class LoadingThread extends Thread { public static final int LOAD_CHARACTER_SERVER = 3; public static final int LOAD_CLIENT_WORLD = 4; public static final int LOAD_DEBUG_RANDOM_SP_WORLD = 5; + public static final int LOAD_LEVEL_EDITOR = 6; + public static final int LOAD_LEVEL = 7; int threadType; @@ -54,6 +56,16 @@ public class LoadingThread extends Thread { case LOAD_DEBUG_RANDOM_SP_WORLD: { DebugSPWorldLoading.loadDebugSPWorld(); } break; + + //loads the level editor + case LOAD_LEVEL_EDITOR: { + LevelEditorLoading.loadLevelEditor(); + } break; + + //loads the save in Globals.currentSave as a level + case LOAD_LEVEL: { + LevelLoading.loadLevel(); + } break; } lock.release(); diff --git a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java index 72e646f7..eddaa2c3 100644 --- a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java +++ b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java @@ -36,6 +36,9 @@ import org.joml.Vector4f; * Utilities for generating foliage */ public class FoliageUtils { + + //the entity type value + public static final int ENTITY_TYPE_FOLIAGE = 3; /** * Spawns a basic foliage object diff --git a/src/main/java/electrosphere/entity/types/object/ObjectUtils.java b/src/main/java/electrosphere/entity/types/object/ObjectUtils.java index d69a3faa..f3457a8e 100644 --- a/src/main/java/electrosphere/entity/types/object/ObjectUtils.java +++ b/src/main/java/electrosphere/entity/types/object/ObjectUtils.java @@ -39,6 +39,9 @@ import electrosphere.server.datacell.utils.ServerEntityTagUtils; import electrosphere.server.poseactor.PoseActor; public class ObjectUtils { + + //the entity type value + public static final int ENTITY_TYPE_OBJECT = 2; public static Entity clientSpawnBasicObject(String type){ ObjectData rawType = Globals.gameConfigCurrent.getObjectTypeLoader().getObject(type); @@ -114,6 +117,8 @@ public class ObjectUtils { //idle tree & generic stuff all objects have rVal.putData(EntityDataStrings.TREE_IDLE, new IdleTree(rVal)); rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); + rVal.putData(EntityDataStrings.ENTITY_TYPE, ENTITY_TYPE_OBJECT); + rVal.putData(EntityDataStrings.ENTITY_SUBTYPE, type); return rVal; } @@ -211,4 +216,25 @@ public class ObjectUtils { return rVal; } + /** + * Checks if the provided entity is an object + * @param entity The entity + * @return true if it is an object, false otherwise + */ + public static boolean isObject(Entity entity){ + if(!entity.containsKey(EntityDataStrings.ENTITY_TYPE)){ + return false; + } + return (int)entity.getData(EntityDataStrings.ENTITY_TYPE) == ENTITY_TYPE_OBJECT; + } + + /** + * Gets the type of object + * @param e the entity + * @return the type + */ + public static String getType(Entity e){ + return (String)EntityUtils.getEntitySubtype(e); + } + } diff --git a/src/main/java/electrosphere/entity/types/structure/StructureUtils.java b/src/main/java/electrosphere/entity/types/structure/StructureUtils.java index 33c86786..9300e3b3 100644 --- a/src/main/java/electrosphere/entity/types/structure/StructureUtils.java +++ b/src/main/java/electrosphere/entity/types/structure/StructureUtils.java @@ -26,6 +26,9 @@ import org.joml.Vector4f; * @author amaterasu */ public class StructureUtils { + + //the entity type value + public static final int ENTITY_TYPE_STRUCTURE = 4; public static Entity clientSpawnBasicStructure(String type, Vector3f position, Quaternionf rotation){ diff --git a/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInGame.java b/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInGame.java index 786c129f..be5406b7 100644 --- a/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInGame.java +++ b/src/main/java/electrosphere/menu/ingame/MenuGeneratorsInGame.java @@ -128,6 +128,7 @@ public class MenuGeneratorsInGame { static void saveWorld(){ if(Globals.serverTerrainManager != null){ Globals.serverTerrainManager.save(Globals.currentSaveName); + Globals.realmManager.save(Globals.currentSaveName); } } diff --git a/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsLevelEditor.java b/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsLevelEditor.java new file mode 100644 index 00000000..d82f47ac --- /dev/null +++ b/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsLevelEditor.java @@ -0,0 +1,173 @@ +package electrosphere.menu.mainmenu; + +import java.util.List; + +import electrosphere.engine.Globals; +import electrosphere.engine.loadingthreads.LoadingThread; +import electrosphere.menu.MenuGenerators; +import electrosphere.menu.WindowUtils; +import electrosphere.renderer.ui.elements.Button; +import electrosphere.renderer.ui.elements.Label; +import electrosphere.renderer.ui.elements.TextInput; +import electrosphere.renderer.ui.elementtypes.ClickableElement; +import electrosphere.renderer.ui.elementtypes.Element; +import electrosphere.renderer.ui.events.ClickEvent; +import electrosphere.renderer.ui.form.FormElement; +import electrosphere.server.saves.SaveUtils; + +/** + * Menu generators for the main menu interactions with the level editor + */ +public class MenuGeneratorsLevelEditor { + + /** + * Creates the top level menu for the level editor + * @return The actual element containing the menu + */ + public static Element createLevelEditorTopMenu(){ + FormElement rVal = new FormElement(); + int screenTop = 150; + + //label (address) + Label usernameLabel = new Label(100,screenTop + 50,1.0f); + usernameLabel.setText("Select Level"); + rVal.addChild(usernameLabel); + + //button (back) + { + Button backButton = new Button(); + Label backLabel = new Label(100,screenTop + 150,1.0f); + backLabel.setText("Back"); + backButton.addChild(backLabel); + rVal.addChild(backButton); + backButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ + WindowUtils.replaceMainMenuContents(MenuGeneratorsTitleMenu.createTitleMenu()); + return false; + }}); + } + + //button (create level) + { + Button createLevelButton = new Button(); + Label createLevelLabel = new Label(100,screenTop + 225,1.0f); + createLevelLabel.setText("Create Level"); + createLevelButton.addChild(createLevelLabel); + rVal.addChild(createLevelButton); + createLevelButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ + //go to create level flow + WindowUtils.replaceMainMenuContents(MenuGeneratorsLevelEditor.createLevelEditorCreationMenu()); + return false; + }}); + } + + //the buttons to load existing levels + List saveNames = SaveUtils.getSaves(); + int i = 0; + for(String saveName : saveNames){ + i++; + + //delete level button + Button deleteButton = new Button(); + Label deleteLabel = new Label(100,screenTop + 225 + 75 * i,1.0f); + deleteLabel.setText("[X]"); + deleteButton.addChild(deleteLabel); + rVal.addChild(deleteButton); + deleteButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ + SaveUtils.deleteSave(saveName); + WindowUtils.replaceMainMenuContents(MenuGeneratorsLevelEditor.createLevelEditorTopMenu()); + return false; + }}); + + + //button (launch level) + Button launchButton = new Button(); + Label launchLabel = new Label(200,screenTop + 225 + 75 * i,1.0f); + launchLabel.setText(saveName); + launchButton.addChild(launchLabel); + rVal.addChild(launchButton); + launchButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ + //launch level + Globals.currentSaveName = saveName; + LoadingThread loadingThread = new LoadingThread(LoadingThread.LOAD_LEVEL); + Globals.loadingThreadsList.add(loadingThread); + Globals.RUN_CLIENT = true; + Globals.RUN_SERVER = true; + loadingThread.start(); + return false; + }}); + } + + return rVal; + } + + + /** + * Creates the level creation menu + * @return The element containing the level creation menu + */ + public static Element createLevelEditorCreationMenu(){ + FormElement rVal = new FormElement(); + int screenTop = 150; + + //label (address) + Label usernameLabel = new Label(100,screenTop + 50,1.0f); + usernameLabel.setText("Create Level"); + rVal.addChild(usernameLabel); + + //button (back) + { + Button backButton = new Button(); + Label backLabel = new Label(100,screenTop + 150,1.0f); + backLabel.setText("Back"); + backButton.addChild(backLabel); + rVal.addChild(backButton); + backButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ + WindowUtils.replaceMainMenuContents(MenuGeneratorsTitleMenu.createTitleMenu()); + return false; + }}); + } + + //label for text input for level name + { + Label levelNameLabel = new Label(100,screenTop + 225,1.0f); + levelNameLabel.setText("Level Name:"); + rVal.addChild(levelNameLabel); + } + + //generate default level name + List saveNames = SaveUtils.getSaves(); + int i = 0; + String defaultSaveName = "defaultLevel_" + i; + while(saveNames.contains(defaultSaveName)){ + i++; + } + + //get level name + TextInput usernameInput = new TextInput(100,screenTop + 300,1.0f); + usernameInput.setText(defaultSaveName); + rVal.addChild(usernameInput); + + //button (create level) + { + Button createLevelButton = new Button(); + Label createLevelLabel = new Label(100,screenTop + 375,1.0f); + createLevelLabel.setText("Create Level"); + createLevelButton.addChild(createLevelLabel); + rVal.addChild(createLevelButton); + createLevelButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ + //launch level editor + Globals.currentSaveName = usernameInput.getText(); + LoadingThread loadingThread = new LoadingThread(LoadingThread.LOAD_LEVEL_EDITOR); + Globals.loadingThreadsList.add(loadingThread); + Globals.RUN_CLIENT = true; + Globals.RUN_SERVER = true; + loadingThread.start(); + return false; + }}); + } + + + return rVal; + } + +} diff --git a/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsTitleMenu.java b/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsTitleMenu.java index 58197d21..a63a9e29 100644 --- a/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsTitleMenu.java +++ b/src/main/java/electrosphere/menu/mainmenu/MenuGeneratorsTitleMenu.java @@ -63,9 +63,20 @@ public class MenuGeneratorsTitleMenu { return false; }}); + //button (static level) + Button staticLevelButton = new Button(); + Label staticLevelLabel = new Label(100,500,1.0f); + staticLevelLabel.setText("Level Editor"); + staticLevelButton.addChild(staticLevelLabel); + rVal.addChild(staticLevelButton); + staticLevelButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){ + WindowUtils.replaceMainMenuContents(MenuGeneratorsLevelEditor.createLevelEditorTopMenu()); + return false; + }}); + //button (options) Button optionsButton = new Button(); - Label optionsLabel = new Label(100,500,1.0f); + Label optionsLabel = new Label(100,575,1.0f); optionsLabel.setText("Options"); optionsButton.addChild(optionsLabel); rVal.addChild(optionsButton); @@ -76,7 +87,7 @@ public class MenuGeneratorsTitleMenu { //button (sp debug) Button uiDebugSPQuickstartButton = new Button(); - Label uiDebugSPQuickstartLabel = new Label(100,575,1.0f); + Label uiDebugSPQuickstartLabel = new Label(100,650,1.0f); uiDebugSPQuickstartLabel.setText("Debug SP Quickstart"); uiDebugSPQuickstartButton.addChild(uiDebugSPQuickstartLabel); rVal.addChild(uiDebugSPQuickstartButton); @@ -91,7 +102,7 @@ public class MenuGeneratorsTitleMenu { //button (ui testing) Button uiTestingButton = new Button(); - Label uiTestingLabel = new Label(100,650,1.0f); + Label uiTestingLabel = new Label(100,725,1.0f); uiTestingLabel.setText("UI Testing"); uiTestingButton.addChild(uiTestingLabel); rVal.addChild(uiTestingButton); diff --git a/src/main/java/electrosphere/server/content/ServerContentManager.java b/src/main/java/electrosphere/server/content/ServerContentManager.java index 3ca905f4..2e7aa3b7 100644 --- a/src/main/java/electrosphere/server/content/ServerContentManager.java +++ b/src/main/java/electrosphere/server/content/ServerContentManager.java @@ -1,29 +1,66 @@ package electrosphere.server.content; +import java.util.List; + import org.joml.Vector3i; import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.server.content.serialization.ContentSerialization; +import electrosphere.server.content.serialization.EntitySerialization; import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.pathfinding.NavMeshUtils; +import electrosphere.server.saves.SaveUtils; +import electrosphere.util.FileUtils; public class ServerContentManager { + //controls whether the manager should generate content on loading a new scene + boolean generateContent = false; - private ServerContentManager(){ - + /** + * Constructor + */ + private ServerContentManager(boolean generateContent){ + this.generateContent = generateContent; } - public static ServerContentManager createServerContentManager(){ - return new ServerContentManager(); + /** + * Creates a server content manager + * @param generateContent if true, will generate content on loading a new scene, otherwise will not + * @return The server content manager + */ + public static ServerContentManager createServerContentManager(boolean generateContent){ + return new ServerContentManager(generateContent); } - - public void generateContentForDataCell(Realm realm, Vector3i worldPos, ServerDataCell cell){ - if(!Globals.serverWorldData.isArena()){ //in other words, if not arena mode - //if on disk (has already been generated) - //else create from scratch - EnvironmentGenerator.generateForest(realm, cell, worldPos, 0); + /** + * Generates content for a given data cell + * @param realm The realm + * @param worldPos The world position + * @param cell The cell + */ + public void generateContentForDataCell(Realm realm, Vector3i worldPos, ServerDataCell cell, String cellKey){ + String fullPath = "/content/" + cellKey + ".dat"; + if(generateContent){ //in other words, if not arena mode + if(FileUtils.checkSavePathExists(Globals.currentSaveName, fullPath)){ + //if on disk (has already been generated) + ContentSerialization contentRaw = FileUtils.loadObjectFromSavePath(Globals.currentSaveName, fullPath, ContentSerialization.class); + hydrateRawContent(realm,cell,contentRaw); + } else { + //else create from scratch + EnvironmentGenerator.generateForest(realm, cell, worldPos, 0); + } + } else { + //just because content wasn't generated doesn't mean there isn't data saved under that key + if(FileUtils.checkSavePathExists(Globals.currentSaveName, fullPath)){ + //if on disk (has already been generated) + ContentSerialization contentRaw = FileUtils.loadObjectFromSavePath(Globals.currentSaveName, fullPath, ContentSerialization.class); + hydrateRawContent(realm,cell,contentRaw); + } } //TODO: generate navmesh // cell.setNavMesh( @@ -36,6 +73,33 @@ public class ServerContentManager { // ); } + /** + * Saves entity content to disk + * @param locationKey the location key to save under + * @param entities the list of entities to save + */ + public void saveContentToDisk(String locationKey, List entities){ + ContentSerialization serialization = ContentSerialization.constructContentSerialization(entities); + String dirPath = SaveUtils.deriveSaveDirectoryPath(Globals.currentSaveName); + String fullPath = dirPath + "/content/" + locationKey + ".dat"; + FileUtils.serializeObjectToFilePath(fullPath, serialization); + } + + /** + * Actually creates the entities from a content serialization + * @param contentRaw The content serialization + */ + public void hydrateRawContent(Realm realm, ServerDataCell serverDataCell, ContentSerialization contentRaw){ + List serializedEntities = contentRaw.getSerializedEntities(); + for(EntitySerialization serializedEntity : serializedEntities){ + switch(serializedEntity.getType()){ + case CreatureUtils.ENTITY_TYPE_CREATURE: { + Entity creature = CreatureUtils.serverSpawnBasicCreature(realm, serializedEntity.getPosition(), serializedEntity.getSubtype(), null); + EntityUtils.getRotation(creature).set(serializedEntity.getRotation()); + } break; + } + } + } } diff --git a/src/main/java/electrosphere/server/content/serialization/ContentSerialization.java b/src/main/java/electrosphere/server/content/serialization/ContentSerialization.java new file mode 100644 index 00000000..fde49d55 --- /dev/null +++ b/src/main/java/electrosphere/server/content/serialization/ContentSerialization.java @@ -0,0 +1,63 @@ +package electrosphere.server.content.serialization; + +import java.util.LinkedList; +import java.util.List; + +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.entity.types.foliage.FoliageUtils; +import electrosphere.entity.types.item.ItemUtils; +import electrosphere.entity.types.object.ObjectUtils; +import electrosphere.entity.types.structure.StructureUtils; + +/** + * Contains all content for a given cell + */ +public class ContentSerialization { + + + //The entities, serialized + List serializedEntities = new LinkedList(); + + /** + * Constructs a content serialization of a given list of entities + * @param entities The entities + * @return The content serialization + */ + public static ContentSerialization constructContentSerialization(List entities){ + ContentSerialization rVal = new ContentSerialization(); + for(Entity entity : entities){ + if(CreatureUtils.isCreature(entity)){ + EntitySerialization serializedEntity = new EntitySerialization(); + serializedEntity.setPosition(EntityUtils.getPosition(entity)); + serializedEntity.setRotation(EntityUtils.getRotation(entity)); + serializedEntity.setType(CreatureUtils.ENTITY_TYPE_CREATURE); + serializedEntity.setSubtype(CreatureUtils.getType(entity)); + rVal.serializedEntities.add(serializedEntity); + } + if(ItemUtils.isItem(entity)){ + throw new UnsupportedOperationException(); + } + if(ObjectUtils.isObject(entity)){ + throw new UnsupportedOperationException(); + } + if(StructureUtils.isStructure(entity)){ + throw new UnsupportedOperationException(); + } + if(FoliageUtils.isFoliage(entity)){ + throw new UnsupportedOperationException(); + } + } + return rVal; + } + + /** + * Gets all serialized entities + * @return the list of serialized entities + */ + public List getSerializedEntities(){ + return serializedEntities; + } + +} diff --git a/src/main/java/electrosphere/server/content/serialization/EntitySerialization.java b/src/main/java/electrosphere/server/content/serialization/EntitySerialization.java new file mode 100644 index 00000000..cb03cdbd --- /dev/null +++ b/src/main/java/electrosphere/server/content/serialization/EntitySerialization.java @@ -0,0 +1,57 @@ +package electrosphere.server.content.serialization; + +import org.joml.Quaterniond; +import org.joml.Vector3d; + +/** + * A serializaed entity + */ +public class EntitySerialization { + + int type; + String subtype; + Vector3d position; + Quaterniond rotation; + + //type getter + public int getType(){ + return type; + } + + //type setter + public void setType(int type){ + this.type = type; + } + + //subtype getter + public String getSubtype(){ + return subtype; + } + + //subtype setter + public void setSubtype(String subtype){ + this.subtype = subtype; + } + + //position getter + public Vector3d getPosition(){ + return position; + } + + //position setter + public void setPosition(Vector3d position){ + this.position = position; + } + + //rotation getter + public Quaterniond getRotation(){ + return rotation; + } + + //rotation setter + public void setRotation(Quaterniond rotation){ + this.rotation = rotation; + } + + +} diff --git a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java index 12a428eb..aed03d9d 100644 --- a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java @@ -2,6 +2,7 @@ package electrosphere.server.datacell; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; @@ -24,6 +25,7 @@ import electrosphere.server.datacell.interfaces.VoxelCellManager; import electrosphere.server.datacell.physics.PhysicsDataCell; import electrosphere.server.fluid.manager.ServerFluidChunk; import electrosphere.server.fluid.manager.ServerFluidManager; +import electrosphere.server.saves.SaveUtils; import electrosphere.server.terrain.manager.ServerTerrainManager; import electrosphere.server.terrain.manager.ServerTerrainChunk; @@ -261,6 +263,8 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager Vector3i worldPos = getCellWorldPosition(cell); String 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()){ EntityUtils.cleanUpEntity(entity); @@ -418,10 +422,11 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager */ private ServerDataCell createServerDataCell(Vector3i worldPos){ ServerDataCell rVal = parent.createNewCell(); - groundDataCells.put(getServerDataCellKey(worldPos),rVal); - LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + getServerDataCellKey(worldPos)); + String cellKey = getServerDataCellKey(worldPos); + groundDataCells.put(cellKey,rVal); + LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + cellKey); cellPositionMap.put(rVal,new Vector3i(worldPos)); - serverContentManager.generateContentForDataCell(parent, worldPos, rVal); + serverContentManager.generateContentForDataCell(parent, worldPos, rVal, cellKey); return rVal; } @@ -507,4 +512,13 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager ); } + @Override + public void save(String saveName) { + for(ServerDataCell cell : loadedCells){ + String key = this.getServerDataCellKey(this.getCellWorldPosition(cell)); + //offload all entities in cell to chunk file + serverContentManager.saveContentToDisk(key, cell.getScene().getEntityList()); + } + } + } diff --git a/src/main/java/electrosphere/server/datacell/Realm.java b/src/main/java/electrosphere/server/datacell/Realm.java index 0c76b57b..e259a8bb 100644 --- a/src/main/java/electrosphere/server/datacell/Realm.java +++ b/src/main/java/electrosphere/server/datacell/Realm.java @@ -169,5 +169,13 @@ public class Realm { collisionEngine.clearCollidableImpulseLists(); } + /** + * Saves all server data cells in the realm to a given save + * @param saveName The name of the save + */ + protected void save(String saveName){ + dataCellManager.save(saveName); + } + } diff --git a/src/main/java/electrosphere/server/datacell/RealmManager.java b/src/main/java/electrosphere/server/datacell/RealmManager.java index 13567d65..b571255e 100644 --- a/src/main/java/electrosphere/server/datacell/RealmManager.java +++ b/src/main/java/electrosphere/server/datacell/RealmManager.java @@ -128,5 +128,15 @@ public class RealmManager { return playerToRealmMap.get(player); } + /** + * Saves all cells in all realms in the realm manager + * @param saveName The name of the save + */ + public void save(String saveName){ + for(Realm realm : realms){ + realm.save(saveName); + } + } + } diff --git a/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java b/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java index b6fa1263..2253cbd6 100644 --- a/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java +++ b/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java @@ -1,5 +1,7 @@ package electrosphere.server.datacell.interfaces; +import java.util.List; + import org.joml.Vector3d; import org.joml.Vector3i; @@ -68,5 +70,11 @@ public interface DataCellManager { * Unloads playerless chunks. Strategy for doing this is defined per data cell manager. */ public void unloadPlayerlessChunks(); + + /** + * Saves the data cell manager + * @param saveName The name of the save + */ + public void save(String saveName); } diff --git a/src/main/java/electrosphere/server/saves/SaveUtils.java b/src/main/java/electrosphere/server/saves/SaveUtils.java index 0b235881..2f993bd4 100644 --- a/src/main/java/electrosphere/server/saves/SaveUtils.java +++ b/src/main/java/electrosphere/server/saves/SaveUtils.java @@ -9,6 +9,7 @@ import electrosphere.server.content.ServerContentManager; import electrosphere.server.db.DatabaseUtils; import electrosphere.server.fluid.generation.ArenaFluidGenerator; import electrosphere.server.fluid.manager.ServerFluidManager; +import electrosphere.server.terrain.generation.ArenaChunkGenerator; import electrosphere.server.terrain.generation.OverworldChunkGenerator; import electrosphere.server.terrain.generation.interfaces.ChunkGenerator; import electrosphere.server.terrain.manager.ServerTerrainManager; @@ -50,6 +51,12 @@ public class SaveUtils { return true; } + + //all directories to create within the save each time it is initialized + private static final String[] directoryStructure = new String[]{ + "/content" + }; + /** * Initializes a save directory, overwrites if one is already there * @param saveName Name of the save @@ -66,12 +73,32 @@ public class SaveUtils { //we for some unknown reason, couldn't make the save dir return false; } + //create full directory structure + for(String subDir : directoryStructure){ + String fullPath = dirPath + subDir; + if(!FileUtils.createDirectory(fullPath)){ + //we for some unknown reason, couldn't make the save dir + return false; + } + } //init db file if(!DatabaseUtils.initCentralDBFile(dirPath)){ return false; } return true; } + + /** + * Deletes a save + * @param saveName The name of the save + */ + public static void deleteSave(String saveName){ + String dirPath = deriveSaveDirectoryPath(saveName); + //check if exists + if(FileUtils.checkFileExists(dirPath)){ + FileUtils.recursivelyDelete(dirPath); + } + } @Deprecated @@ -94,6 +121,7 @@ public class SaveUtils { Globals.dbController.connect(dbFilePath); if(!saveName.equals("arena")){ Globals.serverWorldData = FileUtils.loadObjectFromSavePath(saveName, "world.json", ServerWorldData.class); + Globals.serverTerrainManager = new ServerTerrainManager(Globals.serverWorldData.getWorldSizeDiscrete(), 1, 0, 0, new ArenaChunkGenerator()); Globals.serverTerrainManager.load(saveName); Globals.serverFluidManager = new ServerFluidManager(Globals.serverTerrainManager, 2000, 50, 0, 0, new ArenaFluidGenerator()); } @@ -129,7 +157,7 @@ public class SaveUtils { Globals.serverFluidManager = new ServerFluidManager(Globals.serverTerrainManager, 2000, 50, 0.0f, 0, new ArenaFluidGenerator()); SaveUtils.loadTerrainAndDB(currentSaveName); Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); - Globals.serverContentManager = ServerContentManager.createServerContentManager(); + Globals.serverContentManager = ServerContentManager.createServerContentManager(true); Globals.realmManager.createGriddedRealm(Globals.serverWorldData); return true; } diff --git a/src/main/java/electrosphere/server/terrain/manager/ServerTerrainManager.java b/src/main/java/electrosphere/server/terrain/manager/ServerTerrainManager.java index 157744b9..10b107db 100644 --- a/src/main/java/electrosphere/server/terrain/manager/ServerTerrainManager.java +++ b/src/main/java/electrosphere/server/terrain/manager/ServerTerrainManager.java @@ -117,14 +117,16 @@ public class ServerTerrainManager { * @param saveName The name of the save */ public void save(String saveName){ - ByteBuffer buffer = ByteBuffer.allocate(model.getElevation().length * model.getElevation()[0].length * 4); - FloatBuffer floatView = buffer.asFloatBuffer(); - for(int x = 0; x < model.getElevation().length; x++){ - floatView.put(model.getElevation()[x]); + if(model != null){ + ByteBuffer buffer = ByteBuffer.allocate(model.getElevation().length * model.getElevation()[0].length * 4); + FloatBuffer floatView = buffer.asFloatBuffer(); + for(int x = 0; x < model.getElevation().length; x++){ + floatView.put(model.getElevation()[x]); + } + floatView.flip(); + FileUtils.serializeObjectToSavePath(saveName, "./terrain.json", model); + FileUtils.saveBinaryToSavePath(saveName, "./terrain.dat", buffer.array()); } - floatView.flip(); - FileUtils.saveBinaryToSavePath(saveName, "./terrain.dat", buffer.array()); - FileUtils.serializeObjectToSavePath(saveName, "./terrain.json", model); //for each chunk, save via disk map for(String chunkKey : chunkCacheContents){ ServerTerrainChunk chunk = chunkCache.get(chunkKey); @@ -142,18 +144,20 @@ public class ServerTerrainManager { */ public void load(String saveName){ //load terrain model - model = FileUtils.loadObjectFromSavePath(saveName, "./terrain.json", TerrainModel.class); - chunkGenerator.setModel(model); - byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./terrain.dat"); - ByteBuffer buffer = ByteBuffer.wrap(data); - FloatBuffer floatView = buffer.asFloatBuffer(); - float[][] elevation = new float[Globals.serverWorldData.getWorldSizeDiscrete()][Globals.serverWorldData.getWorldSizeDiscrete()]; - for(int x = 0; x < Globals.serverWorldData.getWorldSizeDiscrete(); x++){ - for(int y = 0; y < Globals.serverWorldData.getWorldSizeDiscrete(); y++){ - elevation[x][y] = floatView.get(); + if(FileUtils.getSaveFile(saveName, "./terrain.json").exists()){ + model = FileUtils.loadObjectFromSavePath(saveName, "./terrain.json", TerrainModel.class); + chunkGenerator.setModel(model); + byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./terrain.dat"); + ByteBuffer buffer = ByteBuffer.wrap(data); + FloatBuffer floatView = buffer.asFloatBuffer(); + float[][] elevation = new float[Globals.serverWorldData.getWorldSizeDiscrete()][Globals.serverWorldData.getWorldSizeDiscrete()]; + for(int x = 0; x < Globals.serverWorldData.getWorldSizeDiscrete(); x++){ + for(int y = 0; y < Globals.serverWorldData.getWorldSizeDiscrete(); y++){ + elevation[x][y] = floatView.get(); + } } + model.setElevationArray(elevation); } - model.setElevationArray(elevation); //load chunk disk map chunkDiskMap = new ChunkDiskMap(); chunkDiskMap.init(saveName); diff --git a/src/main/java/electrosphere/util/FileUtils.java b/src/main/java/electrosphere/util/FileUtils.java index c352a490..11239b34 100644 --- a/src/main/java/electrosphere/util/FileUtils.java +++ b/src/main/java/electrosphere/util/FileUtils.java @@ -264,6 +264,17 @@ public class FileUtils { ex.printStackTrace(); } } + + /** + * Checks if a given file exists in a given save + * @param saveName the name of the save + * @param filePath The path to the file RELATIVE TO THE SAVE DIRECTORY + * @return true if it exists, false otherwise + */ + public static boolean checkSavePathExists(String saveName, String filePath){ + String sanitizedFilePath = sanitizeFilePath(filePath); + return getSaveFile(saveName,sanitizedFilePath).exists(); + } /** * Checks if a directory exists