Fix SP debug mode

This commit is contained in:
austin 2023-07-09 15:49:31 -04:00
parent e225cac5cf
commit 8f61e3e00e
33 changed files with 386 additions and 267 deletions

54
pom.xml
View File

@ -255,7 +255,19 @@
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>java</executable>
<includeProjectDependencies>false</includeProjectDependencies>
<includePluginDependencies>true</includePluginDependencies>
<mainClass>electrosphere.engine.Main</mainClass>
<!-- <classpathScope>compile</classpathScope> -->
<arguments>
<argument>-cp</argument>
<argument>target/classes;target/Renderer-0.1-jar-with-dependencies.jar</argument>
<argument>electrosphere.engine.Main</argument>
</arguments>
<!-- <classesDirectory>${project.basedir}/target/classes</classesDirectory> -->
</configuration>
</execution>
<!-- <execution>
<id>Telephone</id>
@ -272,28 +284,30 @@
</configuration>
</execution> -->
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<id>buildnumber</id>
<phase>validate</phase>
<goals>
<goal>create</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>java</executable>
<includeProjectDependencies>false</includeProjectDependencies>
<includePluginDependencies>true</includePluginDependencies>
<mainClass>electrosphere.engine.Main</mainClass>
<!-- <classpathScope>compile</classpathScope> -->
<arguments>
<argument>-cp</argument>
<argument>target/classes;target/Renderer-0.1-jar-with-dependencies.jar</argument>
<argument>electrosphere.engine.Main</argument>
</arguments>
<!-- <classesDirectory>${project.basedir}/target/classes</classesDirectory> -->
<format>{0,number}</format>
<items>
<item>buildNumber</item>
</items>
<doCheck>false</doCheck>
<doUpdate>false</doUpdate>
<revisionOnScmFailure>unknownbuild</revisionOnScmFailure>
</configuration>
</plugin>
<!-- <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<argLine>-XstartOnFirstThread</argLine>
</configuration>
</plugin> -->
</plugins>
</build>
</project>

View File

@ -60,7 +60,6 @@ public class FluidDrawCell {
rVal.worldPos = worldPos;
rVal.program = program;
rVal.data = data;
System.out.println("Create cell");
return rVal;
}

View File

@ -19,7 +19,7 @@ import electrosphere.renderer.ShaderProgram;
*
* @author satellite
*/
public class DrawCellManager {
public class FluidDrawCellManager {
//the center of this cell manager's array in cell space
@ -78,7 +78,7 @@ public class DrawCellManager {
* @param discreteX The initial discrete position X coordinate
* @param discreteY The initial discrete position Y coordinate
*/
public DrawCellManager(ClientTerrainManager clientTerrainManager, int discreteX, int discreteY, int discreteZ){
public FluidDrawCellManager(ClientTerrainManager clientTerrainManager, int discreteX, int discreteY, int discreteZ){
worldBoundDiscreteMax = (int)(Globals.clientWorldData.getWorldBoundMin().x / Globals.clientWorldData.getDynamicInterpolationRatio() * 1.0f);
cells = new HashSet<FluidDrawCell>();
hasNotRequested = new HashSet<String>();
@ -102,7 +102,7 @@ public class DrawCellManager {
update = true;
}
DrawCellManager(){
FluidDrawCellManager(){
}

View File

@ -61,7 +61,6 @@ public class DrawCell {
rVal.worldPos = worldPos;
rVal.program = program;
rVal.data = data;
System.out.println("Create cell");
return rVal;
}

View File

@ -52,7 +52,7 @@ public class DrawCellManager {
int drawStepdownInterval = 3;
int drawStepdownValue = 25;
double drawRadius = 200;
double drawRadius = 50;
int physicsRadius = 3;
@ -272,6 +272,7 @@ public class DrawCellManager {
updateable.remove(key);
keyCellMap.remove(key);
hasRequested.remove(key);
cell.destroy();
}
}
@ -324,14 +325,12 @@ public class DrawCellManager {
* Updates cells that need updating in this manager
*/
public void update(){
if(update){
if(containsUnrequestedCell() && !containsUndrawableCell()){
updateUnrequestedCell();
} else if(containsUndrawableCell()){
makeCellDrawable();
} else if(containsUpdateableCell()){
updateCellModel();
}
if(containsUnrequestedCell() && !containsUndrawableCell()){
updateUnrequestedCell();
} else if(containsUndrawableCell()){
makeCellDrawable();
} else if(containsUpdateableCell()){
updateCellModel();
}
}

View File

@ -443,7 +443,7 @@ public class Globals {
//init default shaderProgram
defaultMeshShader = ShaderProgram.smart_assemble_shader(false,true);
//init terrain shader program
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain.vs", "/Shaders/terrain2/terrain.fs");
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain2.vs", "/Shaders/terrain2/terrain2.fs");
TerrainChunkModelGeneration.terrainChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/terrain2/terrain2.vs", "/Shaders/terrain2/terrain2.fs");
//init fluid shader program
terrainShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid1/fluid1.vs", "/Shaders/fluid1/fluid1.fs");

View File

@ -238,7 +238,7 @@ public class Main {
/// C L I E N T N E T W O R K I N G S T U F F
///
//Why is this its own function? Just to get the networking code out of main()
if(Globals.RUN_CLIENT && Globals.clientConnection != null){
if(Globals.clientConnection != null){
Globals.clientConnection.parseMessages();
}

View File

@ -119,6 +119,9 @@ public class ClientLoading {
/**
* Inits the client networking thread and socket
*/
private static void initClientThread(){
//start client networking
Thread clientThread = null;
@ -253,6 +256,7 @@ public class ClientLoading {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
// System.out.println("invalid cell");
}
@ -262,6 +266,7 @@ public class ClientLoading {
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
// System.out.println("undrawable");
}

View File

@ -14,6 +14,7 @@ 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.saves.SaveUtils;
import electrosphere.server.terrain.manager.ServerTerrainManager;
@ -30,7 +31,7 @@ public class DebugSPWorldLoading {
WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu());
loadingWindow.setVisible(true);
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO,0.0f,0);
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0);
if(!SaveUtils.getSaves().contains("random_sp_world")){
//
//the juicy server GENERATION part
@ -39,7 +40,7 @@ public class DebugSPWorldLoading {
SaveUtils.createOrOverwriteSave("random_sp_world");
//create terrain
Globals.serverTerrainManager.generate();
Globals.serverTerrainManager.save(SaveUtils.deriveSaveDirectoryPath("random_sp_world"));
Globals.serverTerrainManager.save("random_sp_world");
//create world.json
Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager);
FileUtils.serializeObjectToSavePath("random_sp_world", "./world.json", Globals.serverWorldData);
@ -59,7 +60,7 @@ public class DebugSPWorldLoading {
//initialize the local connection
Globals.clientUsername = "testuser";
Globals.clientPassword = AuthenticationManager.getHashedString("testpass");
LoadingUtils.initLocalConnection();
ServerConnectionHandler serverPlayerConnection = LoadingUtils.initLocalConnection();
//wait for player object creation
while(Globals.playerManager.getPlayers().size() < 1){
try {
@ -85,7 +86,7 @@ public class DebugSPWorldLoading {
}
//spawn player character
LoadingUtils.spawnLocalPlayerTestEntity();
LoadingUtils.spawnLocalPlayerTestEntity(serverPlayerConnection);
//request terrain data
Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestMetadataMessage());

View File

@ -1,6 +1,10 @@
package electrosphere.engine.loadingthreads;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.util.concurrent.TimeUnit;
@ -28,7 +32,9 @@ import electrosphere.game.server.world.MacroData;
import electrosphere.game.server.world.ServerWorldData;
import electrosphere.net.NetUtils;
import electrosphere.net.client.ClientNetworking;
import electrosphere.net.parser.net.message.CharacterMessage;
import electrosphere.net.server.Server;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.GriddedDataCellManager;
import electrosphere.server.datacell.Realm;
@ -54,7 +60,7 @@ public class LoadingUtils {
Actually initialize the terrain manager
*/
float randomDampener = 0.0f; //0.25f;
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO,randomDampener,0);
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,randomDampener,0);
if(Globals.RUN_SERVER){
if(Globals.userSettings.gameplayGenerateWorld()){
Globals.serverTerrainManager.generate();
@ -70,7 +76,6 @@ public class LoadingUtils {
int playerStartX = 0;
int playerStartY = 0;
int discreteSize = Globals.serverTerrainManager.getWorldDiscreteSize();
int chunkSize = Globals.serverTerrainManager.getChunkWidth();
boolean found = false;
for(int x = 0; x < discreteSize; x++){
for(int y = 0; y < discreteSize; y++){
@ -164,25 +169,30 @@ public class LoadingUtils {
}
}
static void initLocalConnection(){
Globals.server = new Server(NetUtils.getPort());
static final int STREAM_BUFFER_SIZE = 32 * 1024 * 1024;
static ServerConnectionHandler initLocalConnection(){
ServerConnectionHandler rVal = null;
try {
Globals.server = new Server(NetUtils.getPort());
//client -> server pipe
PipedInputStream clientInput = new PipedInputStream();
PipedInputStream clientInput = new PipedInputStream(STREAM_BUFFER_SIZE);
PipedOutputStream serverOutput = new PipedOutputStream(clientInput);
//server -> client pipe
PipedInputStream serverInput = new PipedInputStream();
PipedOutputStream clientOutput = new PipedOutputStream(serverInput);
PipedOutputStream clientOutput;
clientOutput = new PipedOutputStream(serverInput);
//start server communication thread
Globals.server.addLocalPlayer(serverInput, serverOutput);
rVal = Globals.server.addLocalPlayer(serverInput, serverOutput);
//start client communication thread
Globals.clientConnection = new ClientNetworking(clientInput,clientOutput);
Thread clientThread = null;
clientThread = new Thread(Globals.clientConnection);
clientThread.start();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rVal;
}
/**
@ -219,7 +229,7 @@ public class LoadingUtils {
/**
* Spawns the character, and sets server side connection player object values to the appropriate chunk
*/
static void spawnLocalPlayerTestEntity(){
static void spawnLocalPlayerTestEntity(ServerConnectionHandler serverPlayerConnection){
//
//Create entity
//
@ -238,11 +248,9 @@ public class LoadingUtils {
template.putValue(attribute.getAttributeId(), attribute.getVariants().get(0).getId());
}
}
Realm realm = Globals.realmManager.getRealms().iterator().next();
//create player
//spawn entity
Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,Globals.spawnPoint,template.getCreatureType(),template);
Globals.playerEntity = newPlayerEntity;
//set player character template
serverPlayerConnection.setCreatureTemplate(template);
Globals.clientConnection.queueOutgoingMessage(CharacterMessage.constructRequestSpawnCharacterMessage());
//set player world-space coordinates
Player playerObject = Globals.playerManager.getPlayerFromId(0);
@ -251,12 +259,6 @@ public class LoadingUtils {
Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.y),
Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z)
));
//set client entity data
Globals.clientPlayerData.setWorldPos(playerObject.getWorldPos());
//initially position entity
ServerEntityUtils.initiallyPositionEntity(realm, newPlayerEntity, new Vector3d(Globals.spawnPoint.x + 1,Globals.spawnPoint.y + 5,Globals.spawnPoint.z + 1));
//add entity to correct cells
realm.getDataCellManager().addPlayerToRealm(playerObject);
}
static void initMacroSimulation(){

View File

@ -15,7 +15,7 @@ public class ServerLoading {
// }
//TODO: Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,randomDampener,0);
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO,0.0f,0);
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0);
SaveUtils.loadSave(Globals.currentSaveName);
// LoadingUtils.initTerrainDataCellManager();
//TODO: set spawnpoint

View File

@ -492,7 +492,6 @@ public class CreatureUtils {
*/
public static Entity serverSpawnBasicCreature(Realm realm, Vector3d position, String type, CreatureTemplate template){
CreatureType rawType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(type);
System.out.println("Creature");
Entity rVal = EntityCreationUtils.createServerEntity(realm, position);
EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath());

View File

@ -44,6 +44,9 @@ public class MacroData {
return rVal;
}
static final int MAX_PLACEMENT_ATTEMPTS = 50;
public static MacroData generateWorld(long seed){
Random random = new Random(seed);
MacroData rVal = new MacroData();
@ -80,6 +83,7 @@ public class MacroData {
List<Vector2i> occupiedStartingPositions = new LinkedList<Vector2i>();
for(Race race : rVal.races){
boolean foundPlacementLocation = false;
int attempts = 0;
while(!foundPlacementLocation){
Vector2i start = new Vector2i(random.nextInt(Globals.serverTerrainManager.getWorldDiscreteSize()),random.nextInt(Globals.serverTerrainManager.getWorldDiscreteSize()));
//are we above sea level?
@ -107,6 +111,10 @@ public class MacroData {
}
}
}
attempts++;
if(attempts > MAX_PLACEMENT_ATTEMPTS){
break;
}
}
}

View File

@ -1,6 +1,7 @@
package electrosphere.game.server.world;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.server.terrain.manager.ServerTerrainManager;
import java.util.List;
@ -67,7 +68,7 @@ public class ServerWorldData {
rVal.type = WorldType.GAME_WORLD;
rVal.worldMinPoint = new Vector3f(0,0,0);
int worldDim = terrainManager.getWorldDiscreteSize() * terrainManager.getChunkWidth();
int worldDim = terrainManager.getWorldDiscreteSize() * ServerTerrainChunk.CHUNK_DIMENSION;
rVal.worldMaxPoint = new Vector3f(worldDim,0,worldDim);
rVal.dynamicInterpolationRatio = terrainManager.getDynamicInterpolationRatio();

View File

@ -130,7 +130,7 @@ public class MenuGenerators {
//create save dir
SaveUtils.createOrOverwriteSave(saveName);
//create and save terrain
ServerTerrainManager terrainManager = new ServerTerrainManager(2000,50,100,0.0f,0);
ServerTerrainManager terrainManager = new ServerTerrainManager(2000,50,0.0f,0);
terrainManager.generate();
terrainManager.save(SaveUtils.deriveSaveDirectoryPath(saveName));
WindowUtils.replaceMainMenuContents(MenuGenerators.createWorldSelectMenu());

View File

@ -164,7 +164,7 @@ public class ClientNetworking implements Runnable{
//disconnected from the server
LoggerInterface.loggerNetworking.WARNING("Disconnected from server");
//close socket
if(socket.isConnected()){
if(socket != null && socket.isConnected()){
try {
socket.close();
} catch (IOException e) {
@ -205,13 +205,13 @@ public class ClientNetworking implements Runnable{
(((ServerMessage)message).getMessageSubtype()) == ServerMessageType.PONG
){
if(this.echoPings == true){
LoggerInterface.loggerNetworking.DEBUG("[Server] New message " + message.getType());
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] New message " + message.getType());
}
} else {
LoggerInterface.loggerNetworking.DEBUG("[Server] New message " + message.getType());
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] New message " + message.getType());
}
} else {
LoggerInterface.loggerNetworking.DEBUG("[Server] New message " + message.getType());
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] New message " + message.getType());
}
}

View File

@ -1,6 +1,6 @@
package electrosphere.net.parser.net.raw;
import electrosphere.net.parser.net.message.NetworkMessage;
package electrosphere.net.parser.net.raw;
import electrosphere.net.parser.net.message.NetworkMessage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@ -15,7 +15,7 @@ public class NetworkParser {
CopyOnWriteArrayList<NetworkMessage> incomingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
CopyOnWriteArrayList<NetworkMessage> outgoingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
CircularByteBuffer incomingByteBuffer = new CircularByteBuffer(64 * 1024 * 124);
CircularByteBuffer incomingByteBuffer = new CircularByteBuffer(64 * 1024 * 1024);
CopyOnWriteArrayList<Byte> outgoingByteQueue = new CopyOnWriteArrayList<Byte>();

View File

@ -90,9 +90,10 @@ public class Server implements Runnable{
}
}
public void addLocalPlayer(InputStream serverInputStream, OutputStream serverOutputStream){
public ServerConnectionHandler addLocalPlayer(InputStream serverInputStream, OutputStream serverOutputStream){
ServerConnectionHandler newClient = new ServerConnectionHandler(serverInputStream,serverOutputStream);
clientMap.put("127.0.0.1", newClient);
new Thread(newClient).start();
return newClient;
}
}

View File

@ -28,6 +28,7 @@ import electrosphere.server.terrain.manager.ServerTerrainChunk;
public class GriddedDataCellManager implements DataCellManager, VoxelCellManager {
//these are going to be the natural ground grid of data cells, but we're going to have more than this
Map<String,ServerDataCell> groundDataCells = new HashMap<String,ServerDataCell>();
Map<ServerDataCell,Vector3i> cellPositionMap = new HashMap<ServerDataCell,Vector3i>();
//loaded cells
Semaphore loadedCellsLock = new Semaphore(1);
Set<ServerDataCell> loadedCells;
@ -211,6 +212,25 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
return playerChangedChunk;
}
//Used for cleaning server data cells no longer in use from the realm
Set<ServerDataCell> toCleanQueue = new HashSet<ServerDataCell>();
/**
* Unloads all chunks that haven't had players in them for a set amount of time
*/
public void unloadPlayerlessChunks(){
//TODO: improve to make have less performance impact
for(ServerDataCell cell : loadedCells){
if(cell.getPlayers().size() < 1){
System.out.println("Unload cell");
toCleanQueue.add(cell);
}
}
for(ServerDataCell cell : toCleanQueue){
parent.deregisterCell(cell);
}
toCleanQueue.clear();
}
/**
* Get data cell at a given real point in this realm
* @param point The real point
@ -341,6 +361,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
private ServerDataCell createServerDataCell(Vector3i worldPos){
ServerDataCell rVal = parent.createNewCell();
groundDataCells.put(getServerDataCellKey(worldPos),rVal);
cellPositionMap.put(rVal,new Vector3i(worldPos));
return rVal;
}
@ -396,4 +417,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
terrainEditLock.release();
}
/**
* Gets the world position of a given data cell
* @param cell The data cell
* @return The world position
*/
private Vector3i getCellWorldPosition(ServerDataCell cell){
return cellPositionMap.get(cell);
}
}

View File

@ -83,24 +83,6 @@ public class Realm {
ServerDataCell cell = Globals.entityDataCellMapper.getEntityDataCell(e);
cell.broadcastNetworkMessage(message);
}
//Used for cleaning server data cells no longer in use from the realm
Set<ServerDataCell> toCleanQueue = new HashSet<ServerDataCell>();
/**
* Unloads all chunks that haven't had players in them for a set amount of time
*/
public void unloadPlayerlessChunks(){
//TODO: improve to make have less performance impact
for(ServerDataCell cell : loadedDataCells){
if(cell.getPlayers().size() < 1){
toCleanQueue.add(cell);
}
}
for(ServerDataCell cell : toCleanQueue){
deregisterCell(cell);
}
toCleanQueue.clear();
}
/**
@ -179,10 +161,7 @@ public class Realm {
dataCellManager.simulate();
//data cell manager update misc variables (player positions, unload not-in-use cells)
if(dataCellManager != null){
// boolean playerHasChangedChunk = dataCellManager.updatePlayerGroundCellPositions();
// if(playerHasChangedChunk){
// dataCellManager.unloadPlayerlessChunks();
// }
dataCellManager.unloadPlayerlessChunks();
}
//clear collidable impulse lists
collisionEngine.clearCollidableImpulseLists();

View File

@ -55,5 +55,10 @@ public interface DataCellManager {
* Calls the simulate function on all loaded cells
*/
public void simulate();
/**
* Unloads playerless chunks. Strategy for doing this is defined per data cell manager.
*/
public void unloadPlayerlessChunks();
}

View File

@ -31,11 +31,11 @@ public class NavMeshUtils {
float currentMax = 0;
int startPos = 0;
int endPos = 0;
for(int x = 0; x < Globals.serverTerrainManager.getAugmentedChunkWidth() - 1; x++){
for(int x = 0; x < ServerTerrainChunk.CHUNK_DIMENSION - 1; x++){
numInCurrent = 0;
currentMin = 0;
currentMax = 0;
for(int y = 0; y < Globals.serverTerrainManager.getAugmentedChunkWidth(); y++){
for(int y = 0; y < ServerTerrainChunk.CHUNK_DIMENSION; y++){
//create node
if(navMeshGeneratorMask[x][y]){
if(numInCurrent > 0){
@ -183,12 +183,12 @@ public class NavMeshUtils {
//why the -1? I think the array fiddling above is causing the bounds to be off normally
//this fixes that
NavCube cube = new NavCube(
box.boundMinX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth(),
box.boundMinX + chunk.getWorldX() * ServerTerrainChunk.CHUNK_DIMENSION,
box.minHeight - 0.5f,
box.boundMinY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth(),
box.boundMaxX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth(),
box.boundMinY + chunk.getWorldY() * ServerTerrainChunk.CHUNK_DIMENSION,
box.boundMaxX + chunk.getWorldX() * ServerTerrainChunk.CHUNK_DIMENSION,
box.maxHeight + 0.5f,
box.boundMaxY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()
box.boundMaxY + chunk.getWorldY() * ServerTerrainChunk.CHUNK_DIMENSION
);
rVal.addNode(cube);
}

View File

@ -1,6 +1,7 @@
package electrosphere.server.pathfinding.blocker;
import electrosphere.engine.Globals;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
*
@ -13,7 +14,7 @@ public class NavBlocker {
boolean[][] heightfieldBlocker;
public NavBlocker(){
heightfieldBlocker = new boolean[Globals.serverTerrainManager.getAugmentedChunkWidth()][Globals.serverTerrainManager.getAugmentedChunkWidth()];
heightfieldBlocker = new boolean[ServerTerrainChunk.CHUNK_DIMENSION][ServerTerrainChunk.CHUNK_DIMENSION];
}
public NavBlocker(boolean[][] field){

View File

@ -89,8 +89,8 @@ public class SaveUtils {
String dbFilePath = FileUtils.sanitizeFilePath(dirPath) + "/central.db";
Globals.dbController.connect(dbFilePath);
if(!saveName.equals("arena")){
Globals.serverTerrainManager.load(saveName);
Globals.serverWorldData = FileUtils.loadObjectFromSavePath(saveName, "world.json", ServerWorldData.class);
Globals.serverTerrainManager.load(saveName);
}
return true;
}
@ -106,7 +106,7 @@ public class SaveUtils {
}
public static boolean loadTerrainAndCreateWorldData(String currentSaveName){
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,ServerTerrainManager.SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO,0.0f,0);
Globals.serverTerrainManager = new ServerTerrainManager(2000,50,0.0f,0);
SaveUtils.loadTerrainAndDB(currentSaveName);
Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager);
Globals.realmManager.createGriddedRealm(Globals.serverWorldData);

View File

@ -0,0 +1,92 @@
package electrosphere.server.terrain.diskcache;
import java.util.Map;
import electrosphere.net.server.Server;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
import electrosphere.util.FileUtils;
/**
* An interface for accessing the disk cache of chunk information
*/
public class ChunkDiskCache {
//The map of world position+chunk type to the file that actually houses that information
Map<String,String> worldPosFileMap;
/**
* Constructor
*/
public ChunkDiskCache(){
}
/**
* Gets a key for a given chunk file based on a world coordinate
* @param worldX The x component
* @param worldY The y component
* @param worldZ The z component
* @return The key
*/
private static String getTerrainChunkKey(int worldX, int worldY, int worldZ){
return worldX + "_" + worldY + "_" + worldZ + "t";
}
/**
* Gets a key for a given chunk file based on a world coordinate
* @param worldX The x component
* @param worldY The y component
* @param worldZ The z component
* @return The key
*/
private static String getFluidChunkKey(int worldX, int worldY, int worldZ){
return worldX + "_" + worldY + "_" + worldZ + "f";
}
/**
* Initializes a diskcache based on a given save name
* @param saveName The save name
*/
public void init(String saveName){
worldPosFileMap = FileUtils.loadObjectFromSavePath(saveName, "ChunkCache.map", Map.class);
}
/**
* Checks if the cache contains a given chunk position
* @param worldX The x component
* @param worldY The y component
* @param worldZ The z component
* @return True if the cache contains the chunk, false otherwise
*/
public boolean containsTerrainAtPosition(int worldX, int worldY, int worldZ){
return worldPosFileMap.containsKey(getTerrainChunkKey(worldX, worldY, worldZ));
}
/**
* Checks if the cache contains a given chunk position
* @param worldX The x component
* @param worldY The y component
* @param worldZ The z component
* @return True if the cache contains the chunk, false otherwise
*/
public boolean containsFluidAtPosition(int worldX, int worldY, int worldZ){
return worldPosFileMap.containsKey(getFluidChunkKey(worldX, worldY, worldZ));
}
/**
* Gets the server terrain chunk from disk if it exists, otherwise returns null
* @param worldX The x coordinate
* @param worldY The y coordinate
* @param worldZ The z coordinate
* @return The server terrain chunk if it exists, null otherwise
*/
public ServerTerrainChunk getTerrainChunk(int worldX, int worldY, int worldZ){
ServerTerrainChunk rVal = null;
if(containsTerrainAtPosition(worldX, worldY, worldZ)){
String fileName = worldPosFileMap.get(getTerrainChunkKey(worldX, worldY, worldZ));
//TODO: implement
}
return rVal;
}
}

View File

@ -49,13 +49,16 @@ public class TerrainEditing {
float distance = (float)new Vector3d(Math.floor(offsetPos.x),Math.floor(offsetPos.y),Math.floor(offsetPos.z)).distance(position);
float currentPositionMagnitude = editMagnitude - distance;
ServerTerrainChunk data = voxelCellManager.getChunkAtPosition(chunkPos);
ServerTerrainChunk data;
if(
voxelPos.x < ServerTerrainChunk.CHUNK_DIMENSION &&
voxelPos.y < ServerTerrainChunk.CHUNK_DIMENSION &&
voxelPos.z < ServerTerrainChunk.CHUNK_DIMENSION &&
voxelPos.x > 0 &&
voxelPos.y > 0 &&
voxelPos.z > 0 &&
currentPositionMagnitude > 0 &&
data != null
(data = voxelCellManager.getChunkAtPosition(chunkPos)) != null
){
float current = data.getWeights()[voxelPos.x][voxelPos.y][voxelPos.z];
//hard clamp so it doesn't go over 1

View File

@ -171,29 +171,29 @@ public class TerrainGenerator {
//create internal renderer
createRenderer();
// createRenderer();
boolean test = true;
while(test){
if(brightnessIncreasing){
if(brightness < 100){
brightness++;
} else {
}
} else {
if(brightness > 0){
brightness--;
} else {
brightnessIncreasing = true;
displayToggle++;
if(displayToggle > 1){
displayToggle = 0;
}
}
}
frame.repaint();
Utilities.sleep(10);
}
// boolean test = true;
// while(test){
// if(brightnessIncreasing){
// if(brightness < 100){
// brightness++;
// } else {
// }
// } else {
// if(brightness > 0){
// brightness--;
// } else {
// brightnessIncreasing = true;
// displayToggle++;
// if(displayToggle > 1){
// displayToggle = 0;
// }
// }
// }
// frame.repaint();
// Utilities.sleep(10);
// }
return rVal;
}

View File

@ -1,20 +1,18 @@
package electrosphere.server.terrain.manager;
import com.google.gson.Gson;
import electrosphere.engine.Globals;
import electrosphere.game.terrain.processing.TerrainInterpolator;
import electrosphere.server.terrain.generation.TerrainGenerator;
import electrosphere.server.terrain.models.ModificationList;
import electrosphere.server.terrain.models.TerrainModel;
import electrosphere.server.terrain.models.TerrainModification;
import electrosphere.engine.Globals;
import electrosphere.util.FileUtils;
import electrosphere.util.Utilities;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@ -36,8 +34,6 @@ public class ServerTerrainManager {
//The vertical multiplier applied to the statically generated terrain
int verticalInterpolationRatio;
int dynamicInterpolationRatio;
float interpolationRandomDampener;
long seed;
@ -59,10 +55,9 @@ public class ServerTerrainManager {
public ServerTerrainManager(int worldSizeDiscrete, int verticalInterpolationRatio, int dynamicInterpolationRatio, float interpolationRandomDampener, long seed){
public ServerTerrainManager(int worldSizeDiscrete, int verticalInterpolationRatio, float interpolationRandomDampener, long seed){
this.worldSizeDiscrete = worldSizeDiscrete;
this.verticalInterpolationRatio = verticalInterpolationRatio;
this.dynamicInterpolationRatio = dynamicInterpolationRatio;
this.chunkCache = new ConcurrentHashMap<String, ServerTerrainChunk>();
this.chunkCacheContents = new CopyOnWriteArrayList<String>();
this.interpolationRandomDampener = interpolationRandomDampener;
@ -77,7 +72,6 @@ public class ServerTerrainManager {
ServerTerrainManager rVal = new ServerTerrainManager();
rVal.worldSizeDiscrete = 2;
rVal.verticalInterpolationRatio = 0;
rVal.dynamicInterpolationRatio = SERVER_TERRAIN_MANAGER_INTERPOLATION_RATIO;
rVal.chunkCache = new ConcurrentHashMap<String, ServerTerrainChunk>();
rVal.chunkCacheContents = new CopyOnWriteArrayList<String>();
rVal.interpolationRandomDampener = 0.0f;
@ -88,115 +82,47 @@ public class ServerTerrainManager {
TerrainGenerator terrainGen = new TerrainGenerator();
terrainGen.setInterpolationRatio(worldSizeDiscrete/200);
terrainGen.setVerticalInterpolationRatio(verticalInterpolationRatio);
terrainGen.setDynamicInterpolationRatio(dynamicInterpolationRatio);
terrainGen.setRandomSeed(seed);
model = terrainGen.generateModel();
model.setInterpolationRandomDampener(interpolationRandomDampener);
}
public void save(String path){
Gson gson = new Gson();
String terrainOutRaw = gson.toJson(model);
try {
Files.write(new File(path + "./terrain.json").toPath(), terrainOutRaw.getBytes());
} catch (IOException ex) {
ex.printStackTrace();
/**
* Saves the terrain model backing this manager to a save file
* @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]);
}
floatView.flip();
FileUtils.saveBinaryToSavePath(saveName, "./terrain.dat", buffer.array());
FileUtils.serializeObjectToSavePath(saveName, "./terrain.json", model);
}
public void load(String saveName){
model = FileUtils.loadObjectFromSavePath(saveName, "./terrain.json", TerrainModel.class);
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);
}
public float[][] getTerrainAtChunk(int x, int y){
return model.getElevationForChunk(x, y);
}
// public ServerTerrainChunk getAugmentedTerrainAtChunk(int x, int y){
// //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
// if(model != null){
// String key = getKey(x,y);
// ServerTerrainChunk returnedChunk;
// if(elevationMapCache.containsKey(key)){
// elevationMapCacheContents.remove(key);
// elevationMapCacheContents.add(0, key);
// returnedChunk = elevationMapCache.get(key);
// return returnedChunk;
// } else {
// float[][] macroValues = model.getRad5MacroValuesAtPosition(x, y);
// long[][] randomizer = model.getRad5RandomizerValuesAtPosition(x, y);
// float[][] heightmap = TerrainInterpolator.getBicubicInterpolatedChunk(
// macroValues,
// randomizer,
// model.getDynamicInterpolationRatio(),
// model.getRandomDampener()
// );
// ModificationList modificationList = model.getModifications(x, y);
// for(TerrainModification modification : modificationList.getModifications()){
// modification.applyToHeightfield(heightmap);
// }
// if(elevationMapCacheContents.size() > cacheSize){
// String oldChunk = elevationMapCacheContents.remove(elevationMapCacheContents.size() - 1);
// elevationMapCache.remove(oldChunk);
// }
// returnedChunk = new ServerTerrainChunk(x, y, heightmap, macroValues, randomizer);
// elevationMapCache.put(key, returnedChunk);
// elevationMapCacheContents.add(key);
// return returnedChunk;
// }
// } else {
// //THIS FIRES IF THERE IS AN ARENA WORLD RUNNING
// return ServerTerrainChunk.getArenaChunk(dynamicInterpolationRatio + 1);
// }
// }
public double getHeightAtPosition(double x, double y, double z){
//get chunk coordinate space of input x,y
// int chunkX = (int)Math.floor(x / dynamicInterpolationRatio);
// int chunkY = (int)Math.floor(y / dynamicInterpolationRatio);
// int chunkZ = (int)Math.floor(z / dynamicInterpolationRatio);
// //get local coordinate space of input x,y
// double localX = x - chunkX * dynamicInterpolationRatio;
// double localY = y - chunkY * dynamicInterpolationRatio;
// double localZ = z - chunkZ * dynamicInterpolationRatio;
// //get chunk elevation map
// float[][] chunkElevationMap = getChunk(chunkX,chunkY,chunkZ).heightMap;
// //floored variants of local values
// int localXf = (int)Math.floor(localX);
// int localYf = (int)Math.floor(localY);
// int localZf = (int)Math.floor(localZ);
// /*
// Average some inner value.
// 01 11
// 0.3 0.4 0.5
// 0.1 0.2 0.3
// 00 10
// */
// //interp elevation from map
// float elevation00 = chunkElevationMap[(int)localX+0][(int)localY+0];
// float elevation10 = chunkElevationMap[(int)localX+1][(int)localY+0];
// float elevation01 = chunkElevationMap[(int)localX+0][(int)localY+1];
// float elevation11 = chunkElevationMap[(int)localX+1][(int)localY+1];
// double rVal =
// (1-(localX-localXf))*(1-(localY-localYf)) * elevation00 +
// ( (localX-localXf))*(1-(localY-localYf)) * elevation10 +
// (1-(localX-localXf))*( (localY-localYf)) * elevation01 +
// ( (localX-localXf))*( (localY-localYf)) * elevation11
// ;
return y;
}
public int getChunkWidth(){
return dynamicInterpolationRatio;
}
public int getAugmentedChunkWidth(){
return dynamicInterpolationRatio + 1;
}
public int getWorldDiscreteSize(){
return worldSizeDiscrete;
@ -229,36 +155,6 @@ public class ServerTerrainManager {
return 0.0f;
}
}
// public float[][] getMacroValues(int x, int y){
// //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
// if(model != null){
// return model.getMacroValuesAtPosition(x, y);
// } else {
// //THIS FIRES IF THERE IS AN ARENA WORLD RUNNING
// return new float[3][3];
// }
// }
// public float[][] getRad5MacroValues(int x, int y){
// //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
// if(model != null){
// return model.getRad5MacroValuesAtPosition(x, y);
// } else {
// //THIS FIRES IF THERE IS AN ARENA WORLD RUNNING
// return new float[5][5];
// }
// }
// public long[][] getRandomizer(int x, int y){
// //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING
// if(model != null){
// return model.getRad5RandomizerValuesAtPosition(x, y);
// } else {
// //THIS FIRES IF THERE IS AN ARENA WORLD RUNNING
// return new long[5][5];
// }
// }
public TerrainModel getModel() {
return model;
@ -294,9 +190,13 @@ public class ServerTerrainManager {
for(int weightX = 0; weightX < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightX++){
for(int weightY = 0; weightY < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightY++){
for(int weightZ = 0; weightZ < ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; weightZ++){
if(weightY < heightmap[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldX + weightX][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldZ + weightZ]){
float height = heightmap[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldX + weightX][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE * worldZ + weightZ];
if(weightY < height){
weights[weightX][weightY][weightZ] = 1;
values[weightX][weightY][weightZ] = 1;
} else if(height == 0 && weightY == 0 && worldY == 0) {
weights[weightX][weightY][weightZ] = 0.1f;
values[weightX][weightY][weightZ] = 1;
} else {
weights[weightX][weightY][weightZ] = -1;
values[weightX][weightY][weightZ] = 0;
@ -304,12 +204,6 @@ public class ServerTerrainManager {
}
}
}
// ModificationList modificationList = model.getModifications(x, y);
// if(modificationList != null){
// for(TerrainModification modification : modificationList.getModifications()){
// heightmap = modification.applyToHeightfield(heightmap);
// }
// }
if(chunkCacheContents.size() > cacheSize){
String oldChunk = chunkCacheContents.remove(chunkCacheContents.size() - 1);
chunkCache.remove(oldChunk);

View File

@ -6,13 +6,16 @@ import java.util.List;
import java.util.Map;
import java.util.Random;
import electrosphere.util.annotation.Exclude;
public class TerrainModel {
int dynamicInterpolationRatio;
float interpolationRandomDampener = 0.4f;
int discreteArrayDimension;
float[][] elevation;
@Exclude
private float[][] elevation;
float realMountainThreshold;
float realOceanThreshold;
@ -345,5 +348,13 @@ public class TerrainModel {
// System.out.println("Got modifications at " + worldX + " " + worldY);
return modifications.get(getModificationKey(worldX, worldY, worldZ));
}
/**
* Sets the elevation array (For instance when read from save file on loading a save)
* @param elevation The elevation array to set to
*/
public void setElevationArray(float[][] elevation){
this.elevation = elevation;
}
}

View File

@ -6,6 +6,7 @@ import com.google.gson.GsonBuilder;
import electrosphere.engine.Main;
import electrosphere.game.data.creature.type.movement.MovementSystem;
import electrosphere.game.data.creature.type.movement.MovementSystemSerializer;
import electrosphere.util.annotation.AnnotationExclusionStrategy;
import java.io.BufferedReader;
import java.io.File;
@ -26,6 +27,8 @@ public class FileUtils {
static {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(MovementSystem.class, new MovementSystemSerializer());
gsonBuilder.addDeserializationExclusionStrategy(new AnnotationExclusionStrategy());
gsonBuilder.addSerializationExclusionStrategy(new AnnotationExclusionStrategy());
gson = gsonBuilder.create();
}
@ -209,6 +212,39 @@ public class FileUtils {
ex.printStackTrace();
}
}
/**
* Reads a binary file as an array of bytes
* @param saveName The save name
* @param pathName The path within the save folder
* @return The array of bytes
*/
public static byte[] loadBinaryFromSavePath(String saveName, String pathName){
byte[] rVal = null;
String sanitizedFilePath = sanitizeFilePath(pathName);
try {
rVal = Files.readAllBytes(getSaveFile(saveName,sanitizedFilePath).toPath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rVal;
}
/**
* Writes a binary file to a save folder's file
* @param saveName The name of the save
* @param pathName The path within the save folder
* @param data The data to write
*/
public static void saveBinaryToSavePath(String saveName, String pathName, byte[] data){
String sanitizedFilePath = sanitizeFilePath(pathName);
try {
Files.write(getSaveFile(saveName,sanitizedFilePath).toPath(), data);
} catch (IOException ex) {
ex.printStackTrace();
}
}
/**
* Checks if a directory exists

View File

@ -0,0 +1,22 @@
package electrosphere.util.annotation;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
/**
* Used to exclude single fields from a gson serialization in a black list manner.
* Refer to https://stackoverflow.com/a/27986860/ for reference for why this works and what it is.
*/
public class AnnotationExclusionStrategy implements ExclusionStrategy {
@Override
public boolean shouldSkipField(FieldAttributes f) {
return f.getAnnotation(Exclude.class) != null;
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
}

View File

@ -0,0 +1,17 @@
package electrosphere.util.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
/**
* Used to exclude single fields from a gson serialization in a black list manner.
* Refer to https://stackoverflow.com/a/27986860/ for reference for why this works and what it is.
*/
public @interface Exclude {
}

View File

@ -19,7 +19,7 @@ public class TerrainViewer {
TerrainModel terrainModel;
ServerTerrainManager terrainManager = new ServerTerrainManager(2000, 1000, 100, 0.05f, new Random().nextLong());
ServerTerrainManager terrainManager = new ServerTerrainManager(2000, 1000, 0.05f, new Random().nextLong());
terrainManager.generate();
terrainModel = terrainManager.getModel();