diff --git a/assets/Models/Wheat1.fbx b/assets/Models/Wheat1.fbx index ac19fc3d..91ced733 100644 Binary files a/assets/Models/Wheat1.fbx and b/assets/Models/Wheat1.fbx differ diff --git a/assets/Models/wheat2.fbx b/assets/Models/wheat2.fbx new file mode 100644 index 00000000..60263545 Binary files /dev/null and b/assets/Models/wheat2.fbx differ diff --git a/assets/Textures/Wheat1stretch.png b/assets/Textures/Wheat1stretch.png deleted file mode 100644 index 34fea034..00000000 Binary files a/assets/Textures/Wheat1stretch.png and /dev/null differ diff --git a/assets/Textures/default_texture_map.json b/assets/Textures/default_texture_map.json index ccebf1dc..0f9df534 100644 --- a/assets/Textures/default_texture_map.json +++ b/assets/Textures/default_texture_map.json @@ -12,10 +12,16 @@ "/Textures/w1.png" ] }, - "Models/Wheat1.fbx": { - "Stalk": [ - "/Textures/Wheat1stretch.png", - "/Textures/Wheat1stretch.png" + "Models/wheat1.fbx": { + "Cube": [ + "/Textures/wheat1.png", + "/Textures/wheat1.png" + ] + }, + "Models/wheat2.fbx": { + "Wheat": [ + "/Textures/wheat2.png", + "/Textures/wheat2.png" ] }, "Models/unitsphere.fbx": { diff --git a/assets/Textures/wheat1.png b/assets/Textures/wheat1.png new file mode 100644 index 00000000..95da0bf9 Binary files /dev/null and b/assets/Textures/wheat1.png differ diff --git a/assets/Textures/wheat2.png b/assets/Textures/wheat2.png new file mode 100644 index 00000000..8c5adec0 Binary files /dev/null and b/assets/Textures/wheat2.png differ diff --git a/src/main/java/electrosphere/engine/LoadingThread.java b/src/main/java/electrosphere/engine/LoadingThread.java index c8ea3713..b732f97a 100644 --- a/src/main/java/electrosphere/engine/LoadingThread.java +++ b/src/main/java/electrosphere/engine/LoadingThread.java @@ -23,6 +23,7 @@ import electrosphere.entity.types.structure.StructureUtils; import electrosphere.game.collision.PhysicsUtils; import electrosphere.game.collision.collidable.Collidable; import electrosphere.game.server.ai.creature.MindlessAttacker; +import electrosphere.game.server.terrain.models.TerrainModification; import electrosphere.game.state.MicroSimulation; import electrosphere.logger.LoggerInterface; import electrosphere.main.Globals; @@ -181,14 +182,13 @@ public class LoadingThread extends Thread { //disable menu input Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.NO_INPUT); - + + //init server arena terrain manager separately + initServerArenaTerrainManager(); //init the data of the world initServerArenaWorldData(); - //init server arena terrain manager separately - initServerArenaTerrainManager(); - //initialize the server thread (server only) if(Globals.RUN_SERVER){ initServerThread(); @@ -291,7 +291,7 @@ public class LoadingThread extends Thread { boolean found = false; for(int x = 0; x < discreteSize; x++){ for(int y = 0; y < discreteSize; y++){ - if(Globals.serverTerrainManager.getDiscreteValue(x, y)>1000){ + if(Globals.serverTerrainManager.getDiscreteValue(x, y)>1800){ playerStartX = x; playerStartY = y; found = true; @@ -328,6 +328,7 @@ public class LoadingThread extends Thread { static void initServerArenaWorldData(){ Globals.serverWorldData = ServerWorldData.createArenaWorld(); Globals.spawnPoint = new Vector3f(1,3,1); + Globals.serverTerrainManager.getChunk(0, 0).addModification(new TerrainModification(0,0,5,5,5)); } static void initServerGameWorldData(){ @@ -491,13 +492,22 @@ public class LoadingThread extends Thread { // } //trees \:D/ - for(int i = 0; i < 10; i++){ - Random rand = new Random(); - String treePath = "Models/tree1.fbx"; - Entity tree = EntityUtils.spawnDrawableEntity(treePath); - EntityUtils.getPosition(tree).set(rand.nextFloat() * 150 + 10, 0, rand.nextFloat() * 150 + 10); -// EntityUtils.getEntityRotation(tree).rotateAxis((float)-Math.PI/2.0f, new Vector3f(1,0,0)); - } +// for(int i = 0; i < 10; i++){ +// Random rand = new Random(); +// String treePath = "Models/tree1.fbx"; +// Entity tree = EntityUtils.spawnDrawableEntity(treePath); +// EntityUtils.getPosition(tree).set(rand.nextFloat() * 150 + 10, 0, rand.nextFloat() * 150 + 10); +//// EntityUtils.getEntityRotation(tree).rotateAxis((float)-Math.PI/2.0f, new Vector3f(1,0,0)); +// } + +// Random rand = new Random(); +// for(int i = 0; i < 1000; i++){ +// String wheatPath = "Models/wheat2.fbx"; +// Entity wheatStalk = EntityUtils.spawnDrawableEntity(wheatPath); +// EntityUtils.getPosition(wheatStalk).set(rand.nextFloat() * 20, 0, rand.nextFloat() * 20); +// EntityUtils.getRotation(wheatStalk).rotateLocalX(-(float)Math.PI/2.0f); +// EntityUtils.getScale(wheatStalk).set(1, 1, 2); +// } // String buildingPath = "Models/building1.fbx"; // Entity building = EntityUtils.spawnDrawableEntity(buildingPath); @@ -531,7 +541,7 @@ public class LoadingThread extends Thread { // CreatureUtils.positionCharacter(Globals.playerCharacter, new Vector3f(10,3,10)); - StructureUtils.spawnBasicStructure("building1", new Vector3f(10,2.4f,15), new Quaternionf().rotateLocalY((float)Math.PI)); +// StructureUtils.spawnBasicStructure("building1", new Vector3f(10,2.4f,15), new Quaternionf().rotateLocalY((float)Math.PI)); } diff --git a/src/main/java/electrosphere/game/client/ClientFunctions.java b/src/main/java/electrosphere/game/client/ClientFunctions.java new file mode 100644 index 00000000..def492f7 --- /dev/null +++ b/src/main/java/electrosphere/game/client/ClientFunctions.java @@ -0,0 +1,16 @@ +package electrosphere.game.client; + +import electrosphere.main.Globals; + +/** + * + * @author amaterasu + */ +public class ClientFunctions { + public static void runClientFunctions(){ + if(Globals.clientTerrainManager != null){ + Globals.clientTerrainManager.handleMessages(); + Globals.clientTerrainManager.ejectLoadedChunks(); + } + } +} diff --git a/src/main/java/electrosphere/game/client/drawcell/DrawCellManager.java b/src/main/java/electrosphere/game/client/drawcell/DrawCellManager.java index 893190ee..f5e69f09 100644 --- a/src/main/java/electrosphere/game/client/drawcell/DrawCellManager.java +++ b/src/main/java/electrosphere/game/client/drawcell/DrawCellManager.java @@ -45,7 +45,7 @@ public class DrawCellManager { int drawRadius = 35; int drawStepdownInterval = 3; - int drawStepdownValue = 25; + int drawStepdownValue = 9; int physicsRadius = 3; @@ -165,7 +165,7 @@ public class DrawCellManager { } else { if(hasRequested[targetX][targetY] == false){ //client should request macro values from server - Globals.clientConnection.queueOutgoingMessage(WorldMessage.constructRequestMacroValuesMessage(currentCellX, currentCellY)); + Globals.clientConnection.queueOutgoingMessage(WorldMessage.constructRequestChunkMessage(currentCellX, currentCellY)); hasRequested[targetX][targetY] = true; } } diff --git a/src/main/java/electrosphere/game/client/terrain/cache/ChunkModification.java b/src/main/java/electrosphere/game/client/terrain/cache/ChunkModification.java new file mode 100644 index 00000000..c7d8d76b --- /dev/null +++ b/src/main/java/electrosphere/game/client/terrain/cache/ChunkModification.java @@ -0,0 +1,48 @@ +package electrosphere.game.client.terrain.cache; + +/** + * + * @author amaterasu + */ +public class ChunkModification { + int worldX; + int worldY; + int locationX; + int locationY; + float value; + + public ChunkModification(int worldX, int worldY, int locationX, int locationY, float value) { + this.worldX = worldX; + this.worldY = worldY; + this.locationX = locationX; + this.locationY = locationY; + this.value = value; + } + + public int getWorldX() { + return worldX; + } + + public int getLocationX() { + return locationX; + } + + public int getLocationY() { + return locationY; + } + + public float getValue() { + return value; + } + + public int getWorldY() { + return worldY; + } + + public float[][] applyModification(float[][] heightmap){ + heightmap[locationX][locationY] = value; + return heightmap; + } + + +} diff --git a/src/main/java/electrosphere/game/client/terrain/cache/ClientTerrainCache.java b/src/main/java/electrosphere/game/client/terrain/cache/ClientTerrainCache.java index 05893043..7625612f 100644 --- a/src/main/java/electrosphere/game/client/terrain/cache/ClientTerrainCache.java +++ b/src/main/java/electrosphere/game/client/terrain/cache/ClientTerrainCache.java @@ -5,6 +5,7 @@ import electrosphere.game.server.terrain.models.TerrainModel; import electrosphere.game.terrain.processing.TerrainInterpolator; import java.util.HashMap; import java.util.LinkedList; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; public class ClientTerrainCache { @@ -20,7 +21,7 @@ public class ClientTerrainCache { int cacheSize; - HashMap cacheMap = new HashMap(); + ConcurrentHashMap cacheMap = new ConcurrentHashMap(); CopyOnWriteArrayList cacheList = new CopyOnWriteArrayList(); @@ -63,6 +64,14 @@ public class ClientTerrainCache { } } + public void addFloatsToCache(int x, int y, float[][] values){ + cacheMap.put(getKey(x,y),values); + while(cacheList.size() > cacheSize){ + String currentChunk = cacheList.remove(0); + cacheMap.remove(currentChunk); + } + } + public String getKey(int x, int y){ diff --git a/src/main/java/electrosphere/game/client/terrain/cache/LoadingChunk.java b/src/main/java/electrosphere/game/client/terrain/cache/LoadingChunk.java new file mode 100644 index 00000000..8d18abe8 --- /dev/null +++ b/src/main/java/electrosphere/game/client/terrain/cache/LoadingChunk.java @@ -0,0 +1,77 @@ +package electrosphere.game.client.terrain.cache; + +import electrosphere.game.client.world.ClientWorldData; +import electrosphere.game.terrain.processing.TerrainInterpolator; +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author amaterasu + */ +public class LoadingChunk { + + int worldX, worldY; + int totalNumMessages; + int numReceivedMessages = 0; + + ClientWorldData clientWorldData; + + float[][] macroValues; + long[][] randomizer; + List modification = new ArrayList(); + + public LoadingChunk(int worldX, int worldY, int numMessages, ClientWorldData clientWorldData){ + this.worldX = worldX; + this.worldY = worldY; + this.totalNumMessages = numMessages; + this.clientWorldData = clientWorldData; + } + + public void addMacroValues(float[][] macroValues){ + this.macroValues = macroValues; + } + + public void addRandomizer(long[][] randomizer){ + this.randomizer = randomizer; + } + + public void addModification(int worldX, int worldY, int locationX, int locationY, float value){ + ChunkModification newModification = new ChunkModification(worldX, worldY, locationX, locationY, value); + modification.add(newModification); + } + + public void incrementMessageCount(){ + numReceivedMessages++; + } + + public boolean isComplete(){ + return numReceivedMessages >= totalNumMessages && macroValues != null && randomizer != null; + } + + public float[][] exportFloats(){ + float[][] heightmap = TerrainInterpolator.getBicubicInterpolatedChunk( + macroValues, + randomizer, + clientWorldData.getDynamicInterpolationRatio(), + clientWorldData.getRandomDampener() + ); + if(modification != null){ + for(ChunkModification modification : modification){ + modification.applyModification(heightmap); + } + } + return heightmap; + } + + public int getWorldX() { + return worldX; + } + + public int getWorldY() { + return worldY; + } + + + +} diff --git a/src/main/java/electrosphere/game/client/terrain/cache/LoadingChunkCache.java b/src/main/java/electrosphere/game/client/terrain/cache/LoadingChunkCache.java new file mode 100644 index 00000000..f9be5ef9 --- /dev/null +++ b/src/main/java/electrosphere/game/client/terrain/cache/LoadingChunkCache.java @@ -0,0 +1,48 @@ +package electrosphere.game.client.terrain.cache; + +import java.util.Collection; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * + * @author amaterasu + */ +public class LoadingChunkCache { + ConcurrentHashMap cacheMap = new ConcurrentHashMap(); + CopyOnWriteArrayList cacheList = new CopyOnWriteArrayList(); + + + public LoadingChunkCache(){ + } + + + //USED TO ADD macro values + public void addLoadingChunkToCache(LoadingChunk chunk){ + cacheMap.put(getKey(chunk.worldX, chunk.worldY),chunk); + } + + public LoadingChunk fetch(String key){ + return cacheMap.get(key); + } + + + public String getKey(int worldX, int worldY){ + return worldX + "-" + worldY; + } + + public boolean containsKey(String key){ + return cacheMap.containsKey(key); + } + + public Collection getChunks(){ + return cacheMap.values(); + } + + public void remove(LoadingChunk chunk){ + cacheMap.remove(getKey(chunk.worldX,chunk.worldY)); + cacheList.remove(getKey(chunk.worldX,chunk.worldY)); + } + +} diff --git a/src/main/java/electrosphere/game/client/terrain/manager/ClientTerrainManager.java b/src/main/java/electrosphere/game/client/terrain/manager/ClientTerrainManager.java index a0f7cf04..f8a19eb0 100644 --- a/src/main/java/electrosphere/game/client/terrain/manager/ClientTerrainManager.java +++ b/src/main/java/electrosphere/game/client/terrain/manager/ClientTerrainManager.java @@ -1,8 +1,13 @@ package electrosphere.game.client.terrain.manager; import electrosphere.game.client.terrain.cache.ClientTerrainCache; +import electrosphere.game.client.terrain.cache.LoadingChunk; +import electrosphere.game.client.terrain.cache.LoadingChunkCache; import electrosphere.game.client.world.ClientWorldData; +import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.WorldMessage; +import java.util.LinkedList; +import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; public class ClientTerrainManager { @@ -17,6 +22,9 @@ public class ClientTerrainManager { //used for caching the macro values ClientTerrainCache terrainCache; + //used for caching loading chunks that are still streaming over the net + LoadingChunkCache loadingChunkCache; + ClientWorldData clientWorldData; @@ -24,72 +32,102 @@ public class ClientTerrainManager { public ClientTerrainManager(ClientWorldData clientWorldData){ this.clientWorldData = clientWorldData; terrainCache = new ClientTerrainCache(CACHE_SIZE,clientWorldData); + loadingChunkCache = new LoadingChunkCache(); } public void handleMessages(){ + List bouncedMessages = new LinkedList(); for(WorldMessage message : messageQueue){ messageQueue.remove(message); switch(message.getMessageSubtype()){ case MACROVALUE: - float[][] macroValues = new float[5][5]; - long[][] randomizer = new long[5][5]; - //macro values - macroValues[0][0] = message.getmacroValue00(); - macroValues[0][1] = message.getmacroValue01(); - macroValues[0][2] = message.getmacroValue02(); - macroValues[0][3] = message.getmacroValue03(); - macroValues[0][4] = message.getmacroValue04(); - macroValues[1][0] = message.getmacroValue10(); - macroValues[1][1] = message.getmacroValue11(); - macroValues[1][2] = message.getmacroValue12(); - macroValues[1][3] = message.getmacroValue13(); - macroValues[1][4] = message.getmacroValue14(); - macroValues[2][0] = message.getmacroValue20(); - macroValues[2][1] = message.getmacroValue21(); - macroValues[2][2] = message.getmacroValue22(); - macroValues[2][3] = message.getmacroValue23(); - macroValues[2][4] = message.getmacroValue24(); - macroValues[3][0] = message.getmacroValue30(); - macroValues[3][1] = message.getmacroValue31(); - macroValues[3][2] = message.getmacroValue32(); - macroValues[3][3] = message.getmacroValue33(); - macroValues[3][4] = message.getmacroValue34(); - macroValues[4][0] = message.getmacroValue40(); - macroValues[4][1] = message.getmacroValue41(); - macroValues[4][2] = message.getmacroValue42(); - macroValues[4][3] = message.getmacroValue43(); - macroValues[4][4] = message.getmacroValue44(); - //randomizer - randomizer[0][0] = message.getrandomizerValue00(); - randomizer[0][1] = message.getrandomizerValue01(); - randomizer[0][2] = message.getrandomizerValue02(); - randomizer[0][3] = message.getrandomizerValue03(); - randomizer[0][4] = message.getrandomizerValue04(); - randomizer[1][0] = message.getrandomizerValue10(); - randomizer[1][1] = message.getrandomizerValue11(); - randomizer[1][2] = message.getrandomizerValue12(); - randomizer[1][3] = message.getrandomizerValue13(); - randomizer[1][4] = message.getrandomizerValue14(); - randomizer[2][0] = message.getrandomizerValue20(); - randomizer[2][1] = message.getrandomizerValue21(); - randomizer[2][2] = message.getrandomizerValue22(); - randomizer[2][3] = message.getrandomizerValue23(); - randomizer[2][4] = message.getrandomizerValue24(); - randomizer[3][0] = message.getrandomizerValue30(); - randomizer[3][1] = message.getrandomizerValue31(); - randomizer[3][2] = message.getrandomizerValue32(); - randomizer[3][3] = message.getrandomizerValue33(); - randomizer[3][4] = message.getrandomizerValue34(); - randomizer[4][0] = message.getrandomizerValue40(); - randomizer[4][1] = message.getrandomizerValue41(); - randomizer[4][2] = message.getrandomizerValue42(); - randomizer[4][3] = message.getrandomizerValue43(); - randomizer[4][4] = message.getrandomizerValue44(); - terrainCache.addChunkValuesToCache(message.getlocationX(), message.getlocationY(), macroValues, randomizer); +// terrainCache.addChunkValuesToCache(message.getlocationX(), message.getlocationY(), macroValues, randomizer); + if(loadingChunkCache.containsKey(loadingChunkCache.getKey(message.getworldX(), message.getworldY()))){ + float[][] macroValues = new float[5][5]; + long[][] randomizer = new long[5][5]; + //macro values + macroValues[0][0] = message.getmacroValue00(); + macroValues[0][1] = message.getmacroValue01(); + macroValues[0][2] = message.getmacroValue02(); + macroValues[0][3] = message.getmacroValue03(); + macroValues[0][4] = message.getmacroValue04(); + macroValues[1][0] = message.getmacroValue10(); + macroValues[1][1] = message.getmacroValue11(); + macroValues[1][2] = message.getmacroValue12(); + macroValues[1][3] = message.getmacroValue13(); + macroValues[1][4] = message.getmacroValue14(); + macroValues[2][0] = message.getmacroValue20(); + macroValues[2][1] = message.getmacroValue21(); + macroValues[2][2] = message.getmacroValue22(); + macroValues[2][3] = message.getmacroValue23(); + macroValues[2][4] = message.getmacroValue24(); + macroValues[3][0] = message.getmacroValue30(); + macroValues[3][1] = message.getmacroValue31(); + macroValues[3][2] = message.getmacroValue32(); + macroValues[3][3] = message.getmacroValue33(); + macroValues[3][4] = message.getmacroValue34(); + macroValues[4][0] = message.getmacroValue40(); + macroValues[4][1] = message.getmacroValue41(); + macroValues[4][2] = message.getmacroValue42(); + macroValues[4][3] = message.getmacroValue43(); + macroValues[4][4] = message.getmacroValue44(); + //randomizer + randomizer[0][0] = message.getrandomizerValue00(); + randomizer[0][1] = message.getrandomizerValue01(); + randomizer[0][2] = message.getrandomizerValue02(); + randomizer[0][3] = message.getrandomizerValue03(); + randomizer[0][4] = message.getrandomizerValue04(); + randomizer[1][0] = message.getrandomizerValue10(); + randomizer[1][1] = message.getrandomizerValue11(); + randomizer[1][2] = message.getrandomizerValue12(); + randomizer[1][3] = message.getrandomizerValue13(); + randomizer[1][4] = message.getrandomizerValue14(); + randomizer[2][0] = message.getrandomizerValue20(); + randomizer[2][1] = message.getrandomizerValue21(); + randomizer[2][2] = message.getrandomizerValue22(); + randomizer[2][3] = message.getrandomizerValue23(); + randomizer[2][4] = message.getrandomizerValue24(); + randomizer[3][0] = message.getrandomizerValue30(); + randomizer[3][1] = message.getrandomizerValue31(); + randomizer[3][2] = message.getrandomizerValue32(); + randomizer[3][3] = message.getrandomizerValue33(); + randomizer[3][4] = message.getrandomizerValue34(); + randomizer[4][0] = message.getrandomizerValue40(); + randomizer[4][1] = message.getrandomizerValue41(); + randomizer[4][2] = message.getrandomizerValue42(); + randomizer[4][3] = message.getrandomizerValue43(); + randomizer[4][4] = message.getrandomizerValue44(); + LoadingChunk inProgressChunk = loadingChunkCache.fetch(loadingChunkCache.getKey(message.getworldX(), message.getworldY())); + inProgressChunk.addMacroValues(macroValues); + inProgressChunk.addRandomizer(randomizer); + inProgressChunk.incrementMessageCount(); + } else { + bouncedMessages.add(message); + } + break; + case CHUNKLOADSTART: + LoadingChunk newChunk = new LoadingChunk(message.getworldX(),message.getworldY(),(int)message.getvalue(),clientWorldData); + loadingChunkCache.addLoadingChunkToCache(newChunk); + newChunk.incrementMessageCount(); + break; + case HEIGHTMAPMODIFICATION: + if(loadingChunkCache.containsKey(loadingChunkCache.getKey(message.getworldX(), message.getworldY()))){ + LoadingChunk inProgressChunk = loadingChunkCache.fetch(loadingChunkCache.getKey(message.getworldX(), message.getworldY())); + inProgressChunk.addModification(message.getworldX(), message.getworldY(), message.getlocationX(), message.getlocationY(), message.getvalue()); + inProgressChunk.incrementMessageCount(); + } else { + bouncedMessages.add(message); + } + break; + default: + LoggerInterface.loggerEngine.WARNING("ClientTerrainManager: unhandled network message of type" + message.getMessageSubtype()); break; } } + for(WorldMessage message : bouncedMessages){ + messageQueue.add(message); + } } public void attachWorldMessage(WorldMessage message){ @@ -146,5 +184,18 @@ public class ClientTerrainManager { return rVal; } + public void ejectLoadedChunks(){ + List chunksToEject = new LinkedList(); + for(LoadingChunk chunk : loadingChunkCache.getChunks()){ + if(chunk.isComplete()){ + float[][] heightMap = chunk.exportFloats(); + terrainCache.addFloatsToCache(chunk.getWorldX(), chunk.getWorldY(), heightMap); + chunksToEject.add(chunk); + } + } + for(LoadingChunk loadedChunk : chunksToEject){ + loadingChunkCache.remove(loadedChunk); + } + } } diff --git a/src/main/java/electrosphere/game/server/terrain/manager/ServerTerrainChunk.java b/src/main/java/electrosphere/game/server/terrain/manager/ServerTerrainChunk.java new file mode 100644 index 00000000..fcdf1e12 --- /dev/null +++ b/src/main/java/electrosphere/game/server/terrain/manager/ServerTerrainChunk.java @@ -0,0 +1,64 @@ +package electrosphere.game.server.terrain.manager; + +import electrosphere.game.server.terrain.models.TerrainModification; +import electrosphere.game.server.terrain.models.TerrainModification; +import java.util.LinkedList; +import java.util.List; + +/** + * + * @author amaterasu + */ +public class ServerTerrainChunk { + int worldX, worldY; + List modifications = new LinkedList(); + float[][] heightMap; + float[][] macroValues; + long[][] randomizer; + + public ServerTerrainChunk(int worldX, int worldY, float[][] heightMap, float[][] macroValues, long[][] randomizer) { + this.worldX = worldX; + this.worldY = worldY; + this.heightMap = heightMap; + this.macroValues = macroValues; + this.randomizer = randomizer; + } + + public static ServerTerrainChunk getArenaChunk(int width){ + float[][] macroValues = new float[5][5]; + long[][] randomizer = new long[5][5]; + float[][] heightmap = new float[width + 1][width + 1]; + ServerTerrainChunk rVal = new ServerTerrainChunk(0, 0, heightmap, macroValues, randomizer); + return rVal; + } + + public int getWorldX() { + return worldX; + } + + public int getWorldY() { + return worldY; + } + + public List getModifications() { + return modifications; + } + + public float[][] getHeightMap() { + return heightMap; + } + + public float[][] getMacroValues() { + return macroValues; + } + + public long[][] getRandomizer() { + return randomizer; + } + + public void addModification(TerrainModification modification){ + modifications.add(modification); + } + + +} diff --git a/src/main/java/electrosphere/game/server/terrain/manager/ServerTerrainManager.java b/src/main/java/electrosphere/game/server/terrain/manager/ServerTerrainManager.java index 1b3bc68a..912eb53c 100644 --- a/src/main/java/electrosphere/game/server/terrain/manager/ServerTerrainManager.java +++ b/src/main/java/electrosphere/game/server/terrain/manager/ServerTerrainManager.java @@ -4,7 +4,9 @@ import com.google.gson.Gson; import electrosphere.game.terrain.processing.TerrainInterpolator; import electrosphere.main.Globals; import electrosphere.game.server.terrain.generation.TerrainGen; +import electrosphere.game.server.terrain.models.ModificationList; import electrosphere.game.server.terrain.models.TerrainModel; +import electrosphere.game.server.terrain.models.TerrainModification; import electrosphere.util.FileLoadingUtils; import electrosphere.util.Utilities; import java.io.File; @@ -39,7 +41,7 @@ public class ServerTerrainManager { //While we incur a penalty with converting ints -> string, think this will //offset regenerating the array every time we want a new one int cacheSize = 50; - HashMap elevationMapCache; + HashMap elevationMapCache; ArrayList elevationMapCacheContents; @@ -98,34 +100,43 @@ public class ServerTerrainManager { return model.getElevationForChunk(x, y); } - public float[][] getAugmentedTerrainAtChunk(int x, int y){ - //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING - if(model != null){ - String targetChunkName = x + "-" + y; - if(elevationMapCache.containsKey(targetChunkName)){ - elevationMapCacheContents.remove(targetChunkName); - elevationMapCacheContents.add(0, targetChunkName); - return elevationMapCache.get(targetChunkName); - } else { - float[][] targetChunk = TerrainInterpolator.getBicubicInterpolatedChunk( - model.getRad5MacroValuesAtPosition(x, y), - model.getRad5RandomizerValuesAtPosition(x, y), - model.getDynamicInterpolationRatio(), - model.getRandomDampener() - ); - if(elevationMapCacheContents.size() > cacheSize){ - String oldChunk = elevationMapCacheContents.remove(elevationMapCacheContents.size() - 1); - elevationMapCache.remove(oldChunk); - } - elevationMapCache.put(targetChunkName, targetChunk); - elevationMapCacheContents.add(targetChunkName); - return targetChunk; - } - } else { - //THIS FIRES IF THERE IS AN ARENA WORLD RUNNING - return new float[dynamicInterpolationRatio + 1][dynamicInterpolationRatio + 1]; - } - } +// 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 float getHeightAtPosition(float x, float y){ //get chunk coordinate space of input x,y @@ -135,7 +146,7 @@ public class ServerTerrainManager { float localX = x - chunkX * dynamicInterpolationRatio; float localY = y - chunkY * dynamicInterpolationRatio; //get chunk elevation map - float[][] chunkElevationMap = getAugmentedTerrainAtChunk(chunkX,chunkY); + float[][] chunkElevationMap = getChunk(chunkX,chunkY).heightMap; //floored variants of local values int localXf = (int)Math.floor(localX); int localYf = (int)Math.floor(localY); @@ -214,28 +225,88 @@ public class ServerTerrainManager { // } // } - 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 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 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; } + public String getKey(int x, int y){ + return x + "-" + y; + } + + public ServerTerrainChunk getChunk(int x, int y){ + if(model != null){ + //THIS FIRES IF THERE IS A MAIN GAME WORLD RUNNING + 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); + if(modificationList != null){ + 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 + 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 { + returnedChunk = ServerTerrainChunk.getArenaChunk(dynamicInterpolationRatio + 1); + elevationMapCache.put(key, returnedChunk); + elevationMapCacheContents.add(key); + return returnedChunk; + } + } + } + + public void deformTerrainAtLocationToValue(int worldX, int worldY, int locationX, int locationY, float value){ + + } + } diff --git a/src/main/java/electrosphere/game/server/terrain/models/ModificationList.java b/src/main/java/electrosphere/game/server/terrain/models/ModificationList.java new file mode 100644 index 00000000..0dcd2e3c --- /dev/null +++ b/src/main/java/electrosphere/game/server/terrain/models/ModificationList.java @@ -0,0 +1,22 @@ +package electrosphere.game.server.terrain.models; + +import java.util.ArrayList; +import java.util.List; + +/** + * + * @author amaterasu + */ +public class ModificationList { + + List modifications = new ArrayList(); + + public List getModifications() { + return modifications; + } + + public void addModification(TerrainModification modification){ + modifications.add(modification); + } + +} diff --git a/src/main/java/electrosphere/game/server/terrain/models/TerrainModel.java b/src/main/java/electrosphere/game/server/terrain/models/TerrainModel.java index 5c9e1daa..e48b16c5 100644 --- a/src/main/java/electrosphere/game/server/terrain/models/TerrainModel.java +++ b/src/main/java/electrosphere/game/server/terrain/models/TerrainModel.java @@ -1,5 +1,8 @@ package electrosphere.game.server.terrain.models; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Random; public class TerrainModel { @@ -14,9 +17,11 @@ public class TerrainModel { float realMountainThreshold; float realOceanThreshold; + HashMap modifications; + TerrainModel() { - + this.modifications = new HashMap(); } public TerrainModel( @@ -34,7 +39,7 @@ public class TerrainModel { this.chunkRandomizer = chunkRandomizer; this.realMountainThreshold = realMountainThreshold; this.realOceanThreshold = realOceanThreshold; - + this.modifications = new HashMap(); } public static TerrainModel constructTerrainModel(int dimension, int dynamicInterpolationRatio){ @@ -366,4 +371,28 @@ public class TerrainModel { return realOceanThreshold; } + public String getModificationKey(int x, int y){ + return x + "-" + y; + } + + public void addModification(TerrainModification modification){ + String key = getModificationKey(modification.worldX,modification.worldY); + ModificationList list; + if(!modifications.containsKey(key)){ + list = new ModificationList(); + modifications.put(key, list); + } else { + list = modifications.get(key); + } + list.addModification(modification); + } + + public boolean containsModificationsAtCoord(int worldX, int worldY){ + return modifications.containsKey(getModificationKey(worldX, worldY)); + } + + public ModificationList getModifications(int worldX, int worldY){ + return modifications.get(getModificationKey(worldX, worldY)); + } + } diff --git a/src/main/java/electrosphere/game/server/terrain/models/TerrainModification.java b/src/main/java/electrosphere/game/server/terrain/models/TerrainModification.java new file mode 100644 index 00000000..fbad74b8 --- /dev/null +++ b/src/main/java/electrosphere/game/server/terrain/models/TerrainModification.java @@ -0,0 +1,48 @@ +package electrosphere.game.server.terrain.models; + +/** + * + * @author amaterasu + */ +public class TerrainModification { + int worldX; + int worldY; + int locationX; + int locationY; + float value; + + public TerrainModification(int worldX, int worldY, int locationX, int locationY, float value) { + this.worldX = worldX; + this.worldY = worldY; + this.locationX = locationX; + this.locationY = locationY; + this.value = value; + } + + public int getWorldX() { + return worldX; + } + + public int getWorldY() { + return worldY; + } + + public int getLocationX() { + return locationX; + } + + public int getLocationY() { + return locationY; + } + + public float getValue() { + return value; + } + + public float[][] applyToHeightfield(float[][] heightfield){ + heightfield[locationX][locationY] = value; + return heightfield; + } + + +} diff --git a/src/main/java/electrosphere/main/Main.java b/src/main/java/electrosphere/main/Main.java index 03257f25..9bbdacaf 100644 --- a/src/main/java/electrosphere/main/Main.java +++ b/src/main/java/electrosphere/main/Main.java @@ -14,6 +14,7 @@ import electrosphere.entity.types.hitbox.HitboxUtils; import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.attach.AttachUtils; import electrosphere.engine.LoadingThread; +import electrosphere.game.client.ClientFunctions; import electrosphere.game.state.MicroSimulation; import electrosphere.logger.LoggerInterface; import electrosphere.renderer.RenderingEngine; @@ -188,6 +189,7 @@ public class Main { if(Globals.microSimulation != null && Globals.microSimulation.isReady()){ Globals.microSimulation.simulate(); } + ClientFunctions.runClientFunctions(); /// diff --git a/src/main/java/electrosphere/net/client/ClientProtocol.java b/src/main/java/electrosphere/net/client/ClientProtocol.java index 983e70f8..06e27bc5 100644 --- a/src/main/java/electrosphere/net/client/ClientProtocol.java +++ b/src/main/java/electrosphere/net/client/ClientProtocol.java @@ -140,11 +140,19 @@ public class ClientProtocol { break; case MACROVALUE: Globals.clientTerrainManager.attachWorldMessage(message); - Globals.clientTerrainManager.handleMessages(); break; case SPAWNPOSITION: Globals.spawnPoint.set(new Vector3f(message.getrealLocationX(),0,message.getrealLocationY())); break; + case CHUNKLOADSTART: + Globals.clientTerrainManager.attachWorldMessage(message); + break; + case HEIGHTMAPMODIFICATION: + Globals.clientTerrainManager.attachWorldMessage(message); + break; + default: + LoggerInterface.loggerNetworking.WARNING("Client networking: Unhandled message of type: " + message.getMessageSubtype()); + break; } } diff --git a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java index 17624a2f..b9803e06 100644 --- a/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/NetworkMessage.java @@ -49,9 +49,9 @@ ENTITY_MESSAGE, rVal = WorldMessage.parseMetadataMessage(byteStream); } break; - case TypeBytes.WORLD_MESSAGE_TYPE_REQUESTMACROVALUES: + case TypeBytes.WORLD_MESSAGE_TYPE_REQUESTCHUNK: if(WorldMessage.canParseMessage(byteStream,secondByte)){ - rVal = WorldMessage.parseRequestMacroValuesMessage(byteStream); + rVal = WorldMessage.parseRequestChunkMessage(byteStream); } break; case TypeBytes.WORLD_MESSAGE_TYPE_UPDATE: @@ -59,11 +59,21 @@ ENTITY_MESSAGE, rVal = WorldMessage.parseUpdateMessage(byteStream); } break; + case TypeBytes.WORLD_MESSAGE_TYPE_CHUNKLOADSTART: + if(WorldMessage.canParseMessage(byteStream,secondByte)){ + rVal = WorldMessage.parsechunkLoadStartMessage(byteStream); + } + break; case TypeBytes.WORLD_MESSAGE_TYPE_MACROVALUE: if(WorldMessage.canParseMessage(byteStream,secondByte)){ rVal = WorldMessage.parseMacroValueMessage(byteStream); } break; + case TypeBytes.WORLD_MESSAGE_TYPE_HEIGHTMAPMODIFICATION: + if(WorldMessage.canParseMessage(byteStream,secondByte)){ + rVal = WorldMessage.parseheightMapModificationMessage(byteStream); + } + break; case TypeBytes.WORLD_MESSAGE_TYPE_SPAWNPOSITION: if(WorldMessage.canParseMessage(byteStream,secondByte)){ rVal = WorldMessage.parseSpawnPositionMessage(byteStream); diff --git a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java index 5ad9e677..b0ce9d58 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java +++ b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java @@ -21,17 +21,21 @@ Message categories World subcategories */ public static final byte WORLD_MESSAGE_TYPE_METADATA = 0; - public static final byte WORLD_MESSAGE_TYPE_REQUESTMACROVALUES = 1; + public static final byte WORLD_MESSAGE_TYPE_REQUESTCHUNK = 1; public static final byte WORLD_MESSAGE_TYPE_UPDATE = 2; - public static final byte WORLD_MESSAGE_TYPE_MACROVALUE = 3; - public static final byte WORLD_MESSAGE_TYPE_SPAWNPOSITION = 4; + public static final byte WORLD_MESSAGE_TYPE_CHUNKLOADSTART = 3; + public static final byte WORLD_MESSAGE_TYPE_MACROVALUE = 4; + public static final byte WORLD_MESSAGE_TYPE_HEIGHTMAPMODIFICATION = 5; + public static final byte WORLD_MESSAGE_TYPE_SPAWNPOSITION = 6; /* World packet sizes */ public static final byte WORLD_MESSAGE_TYPE_METADATA_SIZE = 30; - public static final byte WORLD_MESSAGE_TYPE_REQUESTMACROVALUES_SIZE = 10; + public static final byte WORLD_MESSAGE_TYPE_REQUESTCHUNK_SIZE = 10; public static final byte WORLD_MESSAGE_TYPE_UPDATE_SIZE = 10; + public static final byte WORLD_MESSAGE_TYPE_CHUNKLOADSTART_SIZE = 14; public static final int WORLD_MESSAGE_TYPE_MACROVALUE_SIZE = 310; + public static final byte WORLD_MESSAGE_TYPE_HEIGHTMAPMODIFICATION_SIZE = 22; public static final byte WORLD_MESSAGE_TYPE_SPAWNPOSITION_SIZE = 10; /* Player subcategories diff --git a/src/main/java/electrosphere/net/parser/net/message/WorldMessage.java b/src/main/java/electrosphere/net/parser/net/message/WorldMessage.java index 77e07964..facb4512 100644 --- a/src/main/java/electrosphere/net/parser/net/message/WorldMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/WorldMessage.java @@ -8,9 +8,11 @@ public class WorldMessage extends NetworkMessage { public enum WorldMessageType { METADATA, - REQUESTMACROVALUES, + REQUESTCHUNK, UPDATE, + CHUNKLOADSTART, MACROVALUE, + HEIGHTMAPMODIFICATION, SPAWNPOSITION, } @@ -22,6 +24,9 @@ public class WorldMessage extends NetworkMessage { int worldMinY; int worldMaxX; int worldMaxY; + int worldX; + int worldY; + float value; int locationX; int locationY; float realLocationX; @@ -142,6 +147,30 @@ public class WorldMessage extends NetworkMessage { this.worldMaxY = worldMaxY; } + public int getworldX() { + return worldX; + } + + public void setworldX(int worldX) { + this.worldX = worldX; + } + + public int getworldY() { + return worldY; + } + + public void setworldY(int worldY) { + this.worldY = worldY; + } + + public float getvalue() { + return value; + } + + public void setvalue(float value) { + this.value = value; + } + public int getlocationX() { return locationX; } @@ -587,8 +616,8 @@ public class WorldMessage extends NetworkMessage { } else { return false; } - case TypeBytes.WORLD_MESSAGE_TYPE_REQUESTMACROVALUES: - if(byteStream.size() >= TypeBytes.WORLD_MESSAGE_TYPE_REQUESTMACROVALUES_SIZE){ + case TypeBytes.WORLD_MESSAGE_TYPE_REQUESTCHUNK: + if(byteStream.size() >= TypeBytes.WORLD_MESSAGE_TYPE_REQUESTCHUNK_SIZE){ return true; } else { return false; @@ -599,12 +628,24 @@ public class WorldMessage extends NetworkMessage { } else { return false; } + case TypeBytes.WORLD_MESSAGE_TYPE_CHUNKLOADSTART: + if(byteStream.size() >= TypeBytes.WORLD_MESSAGE_TYPE_CHUNKLOADSTART_SIZE){ + return true; + } else { + return false; + } case TypeBytes.WORLD_MESSAGE_TYPE_MACROVALUE: if(byteStream.size() >= TypeBytes.WORLD_MESSAGE_TYPE_MACROVALUE_SIZE){ return true; } else { return false; } + case TypeBytes.WORLD_MESSAGE_TYPE_HEIGHTMAPMODIFICATION: + if(byteStream.size() >= TypeBytes.WORLD_MESSAGE_TYPE_HEIGHTMAPMODIFICATION_SIZE){ + return true; + } else { + return false; + } case TypeBytes.WORLD_MESSAGE_TYPE_SPAWNPOSITION: if(byteStream.size() >= TypeBytes.WORLD_MESSAGE_TYPE_SPAWNPOSITION_SIZE){ return true; @@ -641,18 +682,18 @@ public class WorldMessage extends NetworkMessage { return rVal; } - public static WorldMessage parseRequestMacroValuesMessage(List byteStream){ - WorldMessage rVal = new WorldMessage(WorldMessageType.REQUESTMACROVALUES); + public static WorldMessage parseRequestChunkMessage(List byteStream){ + WorldMessage rVal = new WorldMessage(WorldMessageType.REQUESTCHUNK); stripPacketHeader(byteStream); - rVal.setlocationX(ByteStreamUtils.popIntFromByteQueue(byteStream)); - rVal.setlocationY(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteStream)); return rVal; } - public static WorldMessage constructRequestMacroValuesMessage(int locationX,int locationY){ - WorldMessage rVal = new WorldMessage(WorldMessageType.REQUESTMACROVALUES); - rVal.setlocationX(locationX); - rVal.setlocationY(locationY); + public static WorldMessage constructRequestChunkMessage(int worldX,int worldY){ + WorldMessage rVal = new WorldMessage(WorldMessageType.REQUESTCHUNK); + rVal.setworldX(worldX); + rVal.setworldY(worldY); rVal.serialize(); return rVal; } @@ -673,11 +714,29 @@ public class WorldMessage extends NetworkMessage { return rVal; } + public static WorldMessage parsechunkLoadStartMessage(List byteStream){ + WorldMessage rVal = new WorldMessage(WorldMessageType.CHUNKLOADSTART); + stripPacketHeader(byteStream); + rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setvalue(ByteStreamUtils.popFloatFromByteQueue(byteStream)); + return rVal; + } + + public static WorldMessage constructchunkLoadStartMessage(int worldX,int worldY,float value){ + WorldMessage rVal = new WorldMessage(WorldMessageType.CHUNKLOADSTART); + rVal.setworldX(worldX); + rVal.setworldY(worldY); + rVal.setvalue(value); + rVal.serialize(); + return rVal; + } + public static WorldMessage parseMacroValueMessage(List byteStream){ WorldMessage rVal = new WorldMessage(WorldMessageType.MACROVALUE); stripPacketHeader(byteStream); - rVal.setlocationX(ByteStreamUtils.popIntFromByteQueue(byteStream)); - rVal.setlocationY(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteStream)); rVal.setmacroValue00(ByteStreamUtils.popFloatFromByteQueue(byteStream)); rVal.setmacroValue01(ByteStreamUtils.popFloatFromByteQueue(byteStream)); rVal.setmacroValue02(ByteStreamUtils.popFloatFromByteQueue(byteStream)); @@ -731,10 +790,10 @@ public class WorldMessage extends NetworkMessage { return rVal; } - public static WorldMessage constructMacroValueMessage(int locationX,int locationY,float macroValue00,float macroValue01,float macroValue02,float macroValue03,float macroValue04,float macroValue10,float macroValue11,float macroValue12,float macroValue13,float macroValue14,float macroValue20,float macroValue21,float macroValue22,float macroValue23,float macroValue24,float macroValue30,float macroValue31,float macroValue32,float macroValue33,float macroValue34,float macroValue40,float macroValue41,float macroValue42,float macroValue43,float macroValue44,long randomizerValue00,long randomizerValue01,long randomizerValue02,long randomizerValue03,long randomizerValue04,long randomizerValue10,long randomizerValue11,long randomizerValue12,long randomizerValue13,long randomizerValue14,long randomizerValue20,long randomizerValue21,long randomizerValue22,long randomizerValue23,long randomizerValue24,long randomizerValue30,long randomizerValue31,long randomizerValue32,long randomizerValue33,long randomizerValue34,long randomizerValue40,long randomizerValue41,long randomizerValue42,long randomizerValue43,long randomizerValue44){ + public static WorldMessage constructMacroValueMessage(int worldX,int worldY,float macroValue00,float macroValue01,float macroValue02,float macroValue03,float macroValue04,float macroValue10,float macroValue11,float macroValue12,float macroValue13,float macroValue14,float macroValue20,float macroValue21,float macroValue22,float macroValue23,float macroValue24,float macroValue30,float macroValue31,float macroValue32,float macroValue33,float macroValue34,float macroValue40,float macroValue41,float macroValue42,float macroValue43,float macroValue44,long randomizerValue00,long randomizerValue01,long randomizerValue02,long randomizerValue03,long randomizerValue04,long randomizerValue10,long randomizerValue11,long randomizerValue12,long randomizerValue13,long randomizerValue14,long randomizerValue20,long randomizerValue21,long randomizerValue22,long randomizerValue23,long randomizerValue24,long randomizerValue30,long randomizerValue31,long randomizerValue32,long randomizerValue33,long randomizerValue34,long randomizerValue40,long randomizerValue41,long randomizerValue42,long randomizerValue43,long randomizerValue44){ WorldMessage rVal = new WorldMessage(WorldMessageType.MACROVALUE); - rVal.setlocationX(locationX); - rVal.setlocationY(locationY); + rVal.setworldX(worldX); + rVal.setworldY(worldY); rVal.setmacroValue00(macroValue00); rVal.setmacroValue01(macroValue01); rVal.setmacroValue02(macroValue02); @@ -789,6 +848,28 @@ public class WorldMessage extends NetworkMessage { return rVal; } + public static WorldMessage parseheightMapModificationMessage(List byteStream){ + WorldMessage rVal = new WorldMessage(WorldMessageType.HEIGHTMAPMODIFICATION); + stripPacketHeader(byteStream); + rVal.setvalue(ByteStreamUtils.popFloatFromByteQueue(byteStream)); + rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setlocationX(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setlocationY(ByteStreamUtils.popIntFromByteQueue(byteStream)); + return rVal; + } + + public static WorldMessage constructheightMapModificationMessage(float value,int worldX,int worldY,int locationX,int locationY){ + WorldMessage rVal = new WorldMessage(WorldMessageType.HEIGHTMAPMODIFICATION); + rVal.setvalue(value); + rVal.setworldX(worldX); + rVal.setworldY(worldY); + rVal.setlocationX(locationX); + rVal.setlocationY(locationY); + rVal.serialize(); + return rVal; + } + public static WorldMessage parseSpawnPositionMessage(List byteStream){ WorldMessage rVal = new WorldMessage(WorldMessageType.SPAWNPOSITION); stripPacketHeader(byteStream); @@ -844,17 +925,17 @@ public class WorldMessage extends NetworkMessage { rawBytes[26+i] = intValues[i]; } break; - case REQUESTMACROVALUES: + case REQUESTCHUNK: rawBytes = new byte[2+4+4]; //message header rawBytes[0] = TypeBytes.MESSAGE_TYPE_WORLD; //entity messaage header - rawBytes[1] = TypeBytes.WORLD_MESSAGE_TYPE_REQUESTMACROVALUES; - intValues = ByteStreamUtils.serializeIntToBytes(locationX); + rawBytes[1] = TypeBytes.WORLD_MESSAGE_TYPE_REQUESTCHUNK; + intValues = ByteStreamUtils.serializeIntToBytes(worldX); for(int i = 0; i < 4; i++){ rawBytes[2+i] = intValues[i]; } - intValues = ByteStreamUtils.serializeIntToBytes(locationY); + intValues = ByteStreamUtils.serializeIntToBytes(worldY); for(int i = 0; i < 4; i++){ rawBytes[6+i] = intValues[i]; } @@ -874,17 +955,35 @@ public class WorldMessage extends NetworkMessage { rawBytes[6+i] = intValues[i]; } break; + case CHUNKLOADSTART: + rawBytes = new byte[2+4+4+4]; + //message header + rawBytes[0] = TypeBytes.MESSAGE_TYPE_WORLD; + //entity messaage header + rawBytes[1] = TypeBytes.WORLD_MESSAGE_TYPE_CHUNKLOADSTART; + intValues = ByteStreamUtils.serializeIntToBytes(worldX); + for(int i = 0; i < 4; i++){ + rawBytes[2+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(worldY); + for(int i = 0; i < 4; i++){ + rawBytes[6+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeFloatToBytes(value); + for(int i = 0; i < 4; i++){ + rawBytes[10+i] = intValues[i]; + } break; case MACROVALUE: rawBytes = new byte[2+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+4+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8]; //message header rawBytes[0] = TypeBytes.MESSAGE_TYPE_WORLD; //entity messaage header rawBytes[1] = TypeBytes.WORLD_MESSAGE_TYPE_MACROVALUE; - intValues = ByteStreamUtils.serializeIntToBytes(locationX); + intValues = ByteStreamUtils.serializeIntToBytes(worldX); for(int i = 0; i < 4; i++){ rawBytes[2+i] = intValues[i]; } - intValues = ByteStreamUtils.serializeIntToBytes(locationY); + intValues = ByteStreamUtils.serializeIntToBytes(worldY); for(int i = 0; i < 4; i++){ rawBytes[6+i] = intValues[i]; } @@ -1064,6 +1163,32 @@ public class WorldMessage extends NetworkMessage { rawBytes[302+i] = intValues[i]; } break; + case HEIGHTMAPMODIFICATION: + rawBytes = new byte[2+4+4+4+4+4]; + //message header + rawBytes[0] = TypeBytes.MESSAGE_TYPE_WORLD; + //entity messaage header + rawBytes[1] = TypeBytes.WORLD_MESSAGE_TYPE_HEIGHTMAPMODIFICATION; + intValues = ByteStreamUtils.serializeFloatToBytes(value); + for(int i = 0; i < 4; i++){ + rawBytes[2+i] = intValues[i]; + } intValues = ByteStreamUtils.serializeIntToBytes(worldX); + for(int i = 0; i < 4; i++){ + rawBytes[6+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(worldY); + for(int i = 0; i < 4; i++){ + rawBytes[10+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(locationX); + for(int i = 0; i < 4; i++){ + rawBytes[14+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(locationY); + for(int i = 0; i < 4; i++){ + rawBytes[18+i] = intValues[i]; + } + break; case SPAWNPOSITION: rawBytes = new byte[2+4+4]; //message header diff --git a/src/main/java/electrosphere/net/server/ServerProtocol.java b/src/main/java/electrosphere/net/server/ServerProtocol.java index 9b55c1c8..844f53c5 100644 --- a/src/main/java/electrosphere/net/server/ServerProtocol.java +++ b/src/main/java/electrosphere/net/server/ServerProtocol.java @@ -2,6 +2,8 @@ package electrosphere.net.server; import electrosphere.entity.Entity; import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.game.server.terrain.manager.ServerTerrainChunk; +import electrosphere.game.server.terrain.models.TerrainModification; import electrosphere.main.Globals; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.NetworkMessage; @@ -58,7 +60,7 @@ public class ServerProtocol { void handleWorldMessage(WorldMessage message){ switch(message.getMessageSubtype()){ - case REQUESTMACROVALUES: + case REQUESTCHUNK: /* int locationX, int locationY, @@ -81,12 +83,23 @@ public class ServerProtocol { long randomizerValue21, long randomizerValue22 */ - float[][] macroValues = Globals.serverTerrainManager.getRad5MacroValues(message.getlocationX(), message.getlocationY()); - long[][] randomizer = Globals.serverTerrainManager.getRandomizer(message.getlocationX(), message.getlocationY()); + + ServerTerrainChunk chunk = Globals.serverTerrainManager.getChunk(message.getworldX(), message.getworldY()); + + float[][] macroValues = chunk.getMacroValues();//Globals.serverTerrainManager.getRad5MacroValues(message.getworldX(), message.getworldY()); + + long[][] randomizer = chunk.getRandomizer();//Globals.serverTerrainManager.getRandomizer(message.getworldX(), message.getworldY()); + + int numMessages = 2 + chunk.getModifications().size(); + + connectionHandler.addMessagetoOutgoingQueue( + WorldMessage.constructchunkLoadStartMessage(message.getworldX(), message.getworldY(), numMessages) + ); + connectionHandler.addMessagetoOutgoingQueue( WorldMessage.constructMacroValueMessage( - message.getlocationX(), - message.getlocationY(), + message.getworldX(), + message.getworldY(), macroValues[0][0], @@ -143,6 +156,18 @@ public class ServerProtocol { randomizer[4][4] ) ); + + for(TerrainModification modification : chunk.getModifications()){ + connectionHandler.addMessagetoOutgoingQueue( + WorldMessage.constructheightMapModificationMessage( + modification.getValue(), + modification.getWorldX(), + modification.getWorldY(), + modification.getLocationX(), + modification.getLocationY() + ) + ); + } break; } } diff --git a/template.json b/template.json index 9f7b15d2..23c0fa35 100644 --- a/template.json +++ b/template.json @@ -56,6 +56,18 @@ "name" : "worldMaxY", "type" : "FIXED_INT" }, + { + "name" : "worldX", + "type" : "FIXED_INT" + }, + { + "name" : "worldY", + "type" : "FIXED_INT" + }, + { + "name" : "value", + "type" : "FIXED_FLOAT" + }, @@ -302,10 +314,10 @@ ] }, { - "messageName" : "RequestMacroValues", + "messageName" : "RequestChunk", "data" : [ - "locationX", - "locationY" + "worldX", + "worldY" ] }, { @@ -315,11 +327,19 @@ "locationY" ] }, + { + "messageName" : "chunkLoadStart", + "data" : [ + "worldX", + "worldY", + "value" + ] + }, { "messageName" : "MacroValue", "data" : [ - "locationX", - "locationY", + "worldX", + "worldY", "macroValue00", "macroValue01", "macroValue02", @@ -372,6 +392,16 @@ "randomizerValue44" ] }, + { + "messageName" : "heightMapModification", + "data" : [ + "value", + "worldX", + "worldY", + "locationX", + "locationY" + ] + }, { "messageName" : "SpawnPosition", "data" : [