rudimentary scene saving
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2024-03-24 21:51:11 -04:00
parent ee6d310e91
commit 45ce4ca9a9
85 changed files with 775 additions and 51 deletions

View File

@ -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

View File

@ -146,6 +146,8 @@ Overhaul mesh class
(03/10/2024) (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 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) (03/12/2024)
Foliage Manager upgrades Foliage Manager upgrades
@ -185,12 +187,23 @@ Physics-controlled objects system
Clean up main method/class Clean up main method/class
- Include Remotery library - 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 Level loading/saving + Basic Editor
- Spin up voxel level (think arena mode) - Spin up voxel level (think arena mode)
- Save voxel level - Save voxel level
# TODO
Level loading/saving + Basic Editor
- Basic editor functionality - Basic editor functionality
- Menu of types of entities to spawn - Menu of types of entities to spawn
- Button to spawn them at cursor - Button to spawn them at cursor
@ -310,8 +323,6 @@ Upgrade terrain editing user experience further
- Lock to axis tools - Lock to axis tools
- Server validation for client request to change terrain - Server validation for client request to change terrain
Bring LWJGL version up to latest
@ -326,11 +337,6 @@ Upgrade terrain generation algorithms
# Eventually # 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) Generic collision engine to support different instances of engine (eg hitboxes vs terrain vs liquids, etc)
- Major refactoring to happen here - Major refactoring to happen here
Procedural Cliff Texture Procedural Cliff Texture
@ -338,8 +344,6 @@ Procedural Cliff Texture
Terrain Chunks: Terrain Chunks:
- Scale textures to be 1 texture per unit of terrain - Scale textures to be 1 texture per unit of terrain
- Texture atlasing (512x512) - 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 Loot Generator
- System that can generate items that would be appropriate reward given some variables - 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' - ie you tell it 'this is this character's stats, this is the relative level of loot I want to provide'

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -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"}

View File

@ -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}}]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -0,0 +1 @@
{"serializedEntities":[]}

View File

@ -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}

View File

@ -49,6 +49,10 @@ public class AuthenticationManager {
public static String getHashedString(String input){ public static String getHashedString(String input){
String rVal = ""; String rVal = "";
if(input == "" || input == null){
input = "asdf";
}
//generate salt //generate salt
char[] charArray = input.toCharArray(); char[] charArray = input.toCharArray();
byte[] salt = new byte[saltLength]; byte[] salt = new byte[saltLength];

View File

@ -64,7 +64,7 @@ public class ArenaLoading {
private static void initServerArenaWorldData(){ private static void initServerArenaWorldData(){
Globals.serverWorldData = ServerWorldData.createArenaWorld(); Globals.serverWorldData = ServerWorldData.createArenaWorld();
Globals.serverContentManager = ServerContentManager.createServerContentManager(); Globals.serverContentManager = ServerContentManager.createServerContentManager(false);
Globals.spawnPoint = new Vector3d(1,0.1,1); Globals.spawnPoint = new Vector3d(1,0.1,1);
// Globals.serverTerrainManager.getChunk(0, 0).addModification(new TerrainModification(0,0,5,5,5)); // Globals.serverTerrainManager.getChunk(0, 0).addModification(new TerrainModification(0,0,5,5,5));
} }

View File

@ -37,29 +37,29 @@ public class DebugSPWorldLoading {
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0, new OverworldChunkGenerator()); Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0, new OverworldChunkGenerator());
Globals.currentSaveName = "random_sp_world"; Globals.currentSaveName = "random_sp_world";
if(!SaveUtils.getSaves().contains("random_sp_world")){ if(!SaveUtils.getSaves().contains(Globals.currentSaveName)){
// //
//the juicy server GENERATION part //the juicy server GENERATION part
// //
//init save structure //init save structure
SaveUtils.createOrOverwriteSave("random_sp_world"); SaveUtils.createOrOverwriteSave(Globals.currentSaveName);
//create terrain //create terrain
Globals.serverTerrainManager.generate(); Globals.serverTerrainManager.generate();
Globals.serverTerrainManager.save("random_sp_world"); Globals.serverTerrainManager.save(Globals.currentSaveName);
//create world.json //create world.json
Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); 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 //create mock fluid sim manager
Globals.serverFluidManager = new ServerFluidManager(Globals.serverTerrainManager, 2000, 50, 0.0f, 0, new ArenaFluidGenerator()); Globals.serverFluidManager = new ServerFluidManager(Globals.serverTerrainManager, 2000, 50, 0.0f, 0, new ArenaFluidGenerator());
} }
//load just-created save //load just-created save
SaveUtils.loadSave("random_sp_world"); SaveUtils.loadSave(Globals.currentSaveName);
//start initializing game datastructures //start initializing game datastructures
// Globals.griddedDataCellManager.init(Globals.serverWorldData); // Globals.griddedDataCellManager.init(Globals.serverWorldData);
//initialize the "virtual" objects simulation //initialize the "virtual" objects simulation
LoadingUtils.initMacroSimulation(); LoadingUtils.initMacroSimulation();
Globals.serverContentManager = ServerContentManager.createServerContentManager(); Globals.serverContentManager = ServerContentManager.createServerContentManager(true);
LoadingUtils.initGriddedRealm(); LoadingUtils.initGriddedRealm();

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -14,6 +14,8 @@ public class LoadingThread extends Thread {
public static final int LOAD_CHARACTER_SERVER = 3; public static final int LOAD_CHARACTER_SERVER = 3;
public static final int LOAD_CLIENT_WORLD = 4; public static final int LOAD_CLIENT_WORLD = 4;
public static final int LOAD_DEBUG_RANDOM_SP_WORLD = 5; 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; int threadType;
@ -54,6 +56,16 @@ public class LoadingThread extends Thread {
case LOAD_DEBUG_RANDOM_SP_WORLD: { case LOAD_DEBUG_RANDOM_SP_WORLD: {
DebugSPWorldLoading.loadDebugSPWorld(); DebugSPWorldLoading.loadDebugSPWorld();
} break; } 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(); lock.release();

View File

@ -36,6 +36,9 @@ import org.joml.Vector4f;
* Utilities for generating foliage * Utilities for generating foliage
*/ */
public class FoliageUtils { public class FoliageUtils {
//the entity type value
public static final int ENTITY_TYPE_FOLIAGE = 3;
/** /**
* Spawns a basic foliage object * Spawns a basic foliage object

View File

@ -39,6 +39,9 @@ import electrosphere.server.datacell.utils.ServerEntityTagUtils;
import electrosphere.server.poseactor.PoseActor; import electrosphere.server.poseactor.PoseActor;
public class ObjectUtils { public class ObjectUtils {
//the entity type value
public static final int ENTITY_TYPE_OBJECT = 2;
public static Entity clientSpawnBasicObject(String type){ public static Entity clientSpawnBasicObject(String type){
ObjectData rawType = Globals.gameConfigCurrent.getObjectTypeLoader().getObject(type); ObjectData rawType = Globals.gameConfigCurrent.getObjectTypeLoader().getObject(type);
@ -114,6 +117,8 @@ public class ObjectUtils {
//idle tree & generic stuff all objects have //idle tree & generic stuff all objects have
rVal.putData(EntityDataStrings.TREE_IDLE, new IdleTree(rVal)); rVal.putData(EntityDataStrings.TREE_IDLE, new IdleTree(rVal));
rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true);
rVal.putData(EntityDataStrings.ENTITY_TYPE, ENTITY_TYPE_OBJECT);
rVal.putData(EntityDataStrings.ENTITY_SUBTYPE, type);
return rVal; return rVal;
} }
@ -211,4 +216,25 @@ public class ObjectUtils {
return rVal; 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);
}
} }

View File

@ -26,6 +26,9 @@ import org.joml.Vector4f;
* @author amaterasu * @author amaterasu
*/ */
public class StructureUtils { 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){ public static Entity clientSpawnBasicStructure(String type, Vector3f position, Quaternionf rotation){

View File

@ -128,6 +128,7 @@ public class MenuGeneratorsInGame {
static void saveWorld(){ static void saveWorld(){
if(Globals.serverTerrainManager != null){ if(Globals.serverTerrainManager != null){
Globals.serverTerrainManager.save(Globals.currentSaveName); Globals.serverTerrainManager.save(Globals.currentSaveName);
Globals.realmManager.save(Globals.currentSaveName);
} }
} }

View File

@ -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<String> 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<String> 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;
}
}

View File

@ -63,9 +63,20 @@ public class MenuGeneratorsTitleMenu {
return false; 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 (options)
Button optionsButton = new Button(); Button optionsButton = new Button();
Label optionsLabel = new Label(100,500,1.0f); Label optionsLabel = new Label(100,575,1.0f);
optionsLabel.setText("Options"); optionsLabel.setText("Options");
optionsButton.addChild(optionsLabel); optionsButton.addChild(optionsLabel);
rVal.addChild(optionsButton); rVal.addChild(optionsButton);
@ -76,7 +87,7 @@ public class MenuGeneratorsTitleMenu {
//button (sp debug) //button (sp debug)
Button uiDebugSPQuickstartButton = new Button(); 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"); uiDebugSPQuickstartLabel.setText("Debug SP Quickstart");
uiDebugSPQuickstartButton.addChild(uiDebugSPQuickstartLabel); uiDebugSPQuickstartButton.addChild(uiDebugSPQuickstartLabel);
rVal.addChild(uiDebugSPQuickstartButton); rVal.addChild(uiDebugSPQuickstartButton);
@ -91,7 +102,7 @@ public class MenuGeneratorsTitleMenu {
//button (ui testing) //button (ui testing)
Button uiTestingButton = new Button(); Button uiTestingButton = new Button();
Label uiTestingLabel = new Label(100,650,1.0f); Label uiTestingLabel = new Label(100,725,1.0f);
uiTestingLabel.setText("UI Testing"); uiTestingLabel.setText("UI Testing");
uiTestingButton.addChild(uiTestingLabel); uiTestingButton.addChild(uiTestingLabel);
rVal.addChild(uiTestingButton); rVal.addChild(uiTestingButton);

View File

@ -1,29 +1,66 @@
package electrosphere.server.content; package electrosphere.server.content;
import java.util.List;
import org.joml.Vector3i; import org.joml.Vector3i;
import electrosphere.engine.Globals; 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.Realm;
import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.pathfinding.NavMeshUtils; import electrosphere.server.pathfinding.NavMeshUtils;
import electrosphere.server.saves.SaveUtils;
import electrosphere.util.FileUtils;
public class ServerContentManager { 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){ * Generates content for a given data cell
if(!Globals.serverWorldData.isArena()){ //in other words, if not arena mode * @param realm The realm
//if on disk (has already been generated) * @param worldPos The world position
//else create from scratch * @param cell The cell
EnvironmentGenerator.generateForest(realm, cell, worldPos, 0); */
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 //TODO: generate navmesh
// cell.setNavMesh( // 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<Entity> 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<EntitySerialization> 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;
}
}
}
} }

View File

@ -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<EntitySerialization> serializedEntities = new LinkedList<EntitySerialization>();
/**
* Constructs a content serialization of a given list of entities
* @param entities The entities
* @return The content serialization
*/
public static ContentSerialization constructContentSerialization(List<Entity> 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<EntitySerialization> getSerializedEntities(){
return serializedEntities;
}
}

View File

@ -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;
}
}

View File

@ -2,6 +2,7 @@ package electrosphere.server.datacell;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
@ -24,6 +25,7 @@ import electrosphere.server.datacell.interfaces.VoxelCellManager;
import electrosphere.server.datacell.physics.PhysicsDataCell; import electrosphere.server.datacell.physics.PhysicsDataCell;
import electrosphere.server.fluid.manager.ServerFluidChunk; import electrosphere.server.fluid.manager.ServerFluidChunk;
import electrosphere.server.fluid.manager.ServerFluidManager; import electrosphere.server.fluid.manager.ServerFluidManager;
import electrosphere.server.saves.SaveUtils;
import electrosphere.server.terrain.manager.ServerTerrainManager; import electrosphere.server.terrain.manager.ServerTerrainManager;
import electrosphere.server.terrain.manager.ServerTerrainChunk; import electrosphere.server.terrain.manager.ServerTerrainChunk;
@ -261,6 +263,8 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
Vector3i worldPos = getCellWorldPosition(cell); Vector3i worldPos = getCellWorldPosition(cell);
String key = getServerDataCellKey(worldPos); String key = getServerDataCellKey(worldPos);
groundDataCells.remove(key); groundDataCells.remove(key);
//offload all entities in cell to chunk file
serverContentManager.saveContentToDisk(key, cell.getScene().getEntityList());
//clear all entities in cell //clear all entities in cell
for(Entity entity : cell.getScene().getEntityList()){ for(Entity entity : cell.getScene().getEntityList()){
EntityUtils.cleanUpEntity(entity); EntityUtils.cleanUpEntity(entity);
@ -418,10 +422,11 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
*/ */
private ServerDataCell createServerDataCell(Vector3i worldPos){ private ServerDataCell createServerDataCell(Vector3i worldPos){
ServerDataCell rVal = parent.createNewCell(); ServerDataCell rVal = parent.createNewCell();
groundDataCells.put(getServerDataCellKey(worldPos),rVal); String cellKey = getServerDataCellKey(worldPos);
LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + getServerDataCellKey(worldPos)); groundDataCells.put(cellKey,rVal);
LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + cellKey);
cellPositionMap.put(rVal,new Vector3i(worldPos)); cellPositionMap.put(rVal,new Vector3i(worldPos));
serverContentManager.generateContentForDataCell(parent, worldPos, rVal); serverContentManager.generateContentForDataCell(parent, worldPos, rVal, cellKey);
return rVal; 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());
}
}
} }

View File

@ -169,5 +169,13 @@ public class Realm {
collisionEngine.clearCollidableImpulseLists(); 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);
}
} }

View File

@ -128,5 +128,15 @@ public class RealmManager {
return playerToRealmMap.get(player); 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);
}
}
} }

View File

@ -1,5 +1,7 @@
package electrosphere.server.datacell.interfaces; package electrosphere.server.datacell.interfaces;
import java.util.List;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3i; import org.joml.Vector3i;
@ -68,5 +70,11 @@ public interface DataCellManager {
* Unloads playerless chunks. Strategy for doing this is defined per data cell manager. * Unloads playerless chunks. Strategy for doing this is defined per data cell manager.
*/ */
public void unloadPlayerlessChunks(); public void unloadPlayerlessChunks();
/**
* Saves the data cell manager
* @param saveName The name of the save
*/
public void save(String saveName);
} }

View File

@ -9,6 +9,7 @@ import electrosphere.server.content.ServerContentManager;
import electrosphere.server.db.DatabaseUtils; import electrosphere.server.db.DatabaseUtils;
import electrosphere.server.fluid.generation.ArenaFluidGenerator; import electrosphere.server.fluid.generation.ArenaFluidGenerator;
import electrosphere.server.fluid.manager.ServerFluidManager; import electrosphere.server.fluid.manager.ServerFluidManager;
import electrosphere.server.terrain.generation.ArenaChunkGenerator;
import electrosphere.server.terrain.generation.OverworldChunkGenerator; import electrosphere.server.terrain.generation.OverworldChunkGenerator;
import electrosphere.server.terrain.generation.interfaces.ChunkGenerator; import electrosphere.server.terrain.generation.interfaces.ChunkGenerator;
import electrosphere.server.terrain.manager.ServerTerrainManager; import electrosphere.server.terrain.manager.ServerTerrainManager;
@ -50,6 +51,12 @@ public class SaveUtils {
return true; 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 * Initializes a save directory, overwrites if one is already there
* @param saveName Name of the save * @param saveName Name of the save
@ -66,12 +73,32 @@ public class SaveUtils {
//we for some unknown reason, couldn't make the save dir //we for some unknown reason, couldn't make the save dir
return false; 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 //init db file
if(!DatabaseUtils.initCentralDBFile(dirPath)){ if(!DatabaseUtils.initCentralDBFile(dirPath)){
return false; return false;
} }
return true; 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 @Deprecated
@ -94,6 +121,7 @@ public class SaveUtils {
Globals.dbController.connect(dbFilePath); Globals.dbController.connect(dbFilePath);
if(!saveName.equals("arena")){ if(!saveName.equals("arena")){
Globals.serverWorldData = FileUtils.loadObjectFromSavePath(saveName, "world.json", ServerWorldData.class); 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.serverTerrainManager.load(saveName);
Globals.serverFluidManager = new ServerFluidManager(Globals.serverTerrainManager, 2000, 50, 0, 0, new ArenaFluidGenerator()); 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()); Globals.serverFluidManager = new ServerFluidManager(Globals.serverTerrainManager, 2000, 50, 0.0f, 0, new ArenaFluidGenerator());
SaveUtils.loadTerrainAndDB(currentSaveName); SaveUtils.loadTerrainAndDB(currentSaveName);
Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager);
Globals.serverContentManager = ServerContentManager.createServerContentManager(); Globals.serverContentManager = ServerContentManager.createServerContentManager(true);
Globals.realmManager.createGriddedRealm(Globals.serverWorldData); Globals.realmManager.createGriddedRealm(Globals.serverWorldData);
return true; return true;
} }

View File

@ -117,14 +117,16 @@ public class ServerTerrainManager {
* @param saveName The name of the save * @param saveName The name of the save
*/ */
public void save(String saveName){ public void save(String saveName){
ByteBuffer buffer = ByteBuffer.allocate(model.getElevation().length * model.getElevation()[0].length * 4); if(model != null){
FloatBuffer floatView = buffer.asFloatBuffer(); ByteBuffer buffer = ByteBuffer.allocate(model.getElevation().length * model.getElevation()[0].length * 4);
for(int x = 0; x < model.getElevation().length; x++){ FloatBuffer floatView = buffer.asFloatBuffer();
floatView.put(model.getElevation()[x]); 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 each chunk, save via disk map
for(String chunkKey : chunkCacheContents){ for(String chunkKey : chunkCacheContents){
ServerTerrainChunk chunk = chunkCache.get(chunkKey); ServerTerrainChunk chunk = chunkCache.get(chunkKey);
@ -142,18 +144,20 @@ public class ServerTerrainManager {
*/ */
public void load(String saveName){ public void load(String saveName){
//load terrain model //load terrain model
model = FileUtils.loadObjectFromSavePath(saveName, "./terrain.json", TerrainModel.class); if(FileUtils.getSaveFile(saveName, "./terrain.json").exists()){
chunkGenerator.setModel(model); model = FileUtils.loadObjectFromSavePath(saveName, "./terrain.json", TerrainModel.class);
byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./terrain.dat"); chunkGenerator.setModel(model);
ByteBuffer buffer = ByteBuffer.wrap(data); byte[] data = FileUtils.loadBinaryFromSavePath(saveName, "./terrain.dat");
FloatBuffer floatView = buffer.asFloatBuffer(); ByteBuffer buffer = ByteBuffer.wrap(data);
float[][] elevation = new float[Globals.serverWorldData.getWorldSizeDiscrete()][Globals.serverWorldData.getWorldSizeDiscrete()]; FloatBuffer floatView = buffer.asFloatBuffer();
for(int x = 0; x < Globals.serverWorldData.getWorldSizeDiscrete(); x++){ float[][] elevation = new float[Globals.serverWorldData.getWorldSizeDiscrete()][Globals.serverWorldData.getWorldSizeDiscrete()];
for(int y = 0; y < Globals.serverWorldData.getWorldSizeDiscrete(); y++){ for(int x = 0; x < Globals.serverWorldData.getWorldSizeDiscrete(); x++){
elevation[x][y] = floatView.get(); for(int y = 0; y < Globals.serverWorldData.getWorldSizeDiscrete(); y++){
elevation[x][y] = floatView.get();
}
} }
model.setElevationArray(elevation);
} }
model.setElevationArray(elevation);
//load chunk disk map //load chunk disk map
chunkDiskMap = new ChunkDiskMap(); chunkDiskMap = new ChunkDiskMap();
chunkDiskMap.init(saveName); chunkDiskMap.init(saveName);

View File

@ -264,6 +264,17 @@ public class FileUtils {
ex.printStackTrace(); 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 * Checks if a directory exists