diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 594fa480..9b7d11e2 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1100,6 +1100,11 @@ Fix backing out to main menu Refactor ShaderProgram -> VisualShader Break out shader uniform setting into shared file Fix being able to walk off far side of the world (ie in level editor) +Fix chunks saving to disk in wrong stride +Fix server terrain generation lock spinning on loading terrain from disk +Fix crosshair NPE when camera undefined +Fix ray casting entity filtering bug +Fix ClientTerrainManager concurrent editing bug # TODO diff --git a/src/main/java/electrosphere/client/entity/crosshair/Crosshair.java b/src/main/java/electrosphere/client/entity/crosshair/Crosshair.java index 14a6847b..1a127193 100644 --- a/src/main/java/electrosphere/client/entity/crosshair/Crosshair.java +++ b/src/main/java/electrosphere/client/entity/crosshair/Crosshair.java @@ -31,7 +31,7 @@ public class Crosshair { static final float TARGET_MAX_DIST = 1; public static void checkTargetable(){ - if(crossHairEntity != null && Globals.playerEntity != null){ + if(crossHairEntity != null && Globals.playerEntity != null && Globals.playerCamera != null){ Vector3d parentPos = EntityUtils.getPosition(Globals.playerEntity); // if(currentTarget == null){ if(!crosshairActive){ diff --git a/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java b/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java index 15b2db12..c98985f0 100644 --- a/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java +++ b/src/main/java/electrosphere/client/terrain/manager/ClientTerrainManager.java @@ -78,6 +78,11 @@ public class ClientTerrainManager { * Tracks what outgoing requests are currently active */ Map requestedMap = new HashMap(); + + /** + * Used to clear the request map + */ + List toClearFailedRequests = new LinkedList(); /** * Constructor @@ -178,11 +183,17 @@ public class ClientTerrainManager { for(Long key : this.requestedMap.keySet()){ int duration = this.requestedMap.get(key); if(duration > FAILED_REQUEST_THRESHOLD){ - this.requestedMap.remove(key); + toClearFailedRequests.add(key); } else { this.requestedMap.put(key,duration + 1); } } + if(this.toClearFailedRequests.size() > 0){ + for(Long key : toClearFailedRequests){ + this.requestedMap.remove(key); + } + this.toClearFailedRequests.clear(); + } lock.release(); Globals.profiler.endCpuSample(); } diff --git a/src/main/java/electrosphere/collision/RayCastCallback.java b/src/main/java/electrosphere/collision/RayCastCallback.java index 463227af..1b12d3d9 100644 --- a/src/main/java/electrosphere/collision/RayCastCallback.java +++ b/src/main/java/electrosphere/collision/RayCastCallback.java @@ -95,8 +95,8 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) { ) ) ) && - collidable1 != null && collidable1.getParent() != Globals.playerEntity && //don't self cast -- should work on both server and client - collidable2 != null && collidable2.getParent() != Globals.playerEntity //don't self cast -- should work on both server and client + (collidable1 == null || collidable1 != null && collidable1.getParent() != Globals.playerEntity) && //don't self cast -- should work on both server and client + (collidable2 == null || collidable2 != null && collidable2.getParent() != Globals.playerEntity) //don't self cast -- should work on both server and client ){ //calculate collisions int numc = OdeHelper.collide(o1,o2,MAX_CONTACTS,contacts.getGeomBuffer()); diff --git a/src/main/java/electrosphere/engine/loadingthreads/MainMenuLoading.java b/src/main/java/electrosphere/engine/loadingthreads/MainMenuLoading.java index 2d99ceed..21b6ca0c 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/MainMenuLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/MainMenuLoading.java @@ -7,6 +7,7 @@ import electrosphere.engine.Globals; import electrosphere.engine.signal.Signal.SignalType; import electrosphere.engine.threads.LabeledThread.ThreadLabel; import electrosphere.renderer.ui.elements.Window; +import electrosphere.server.datacell.RealmManager; /** * Loading thread that returns the client to the main menu @@ -47,8 +48,10 @@ public class MainMenuLoading { * Resets the client state */ private static void resetClientState(){ + Globals.playerEntity = null; Globals.clientSimulation = null; Globals.clientConnection.setShouldDisconnect(true); + Globals.renderingEngine.getPostProcessingPipeline().setApplyBlur(false); } /** @@ -59,7 +62,7 @@ public class MainMenuLoading { Globals.server = null; Globals.serverSynchronizationManager = null; Globals.realmManager.reset(); - Globals.realmManager = null; + Globals.realmManager = new RealmManager(); Globals.macroSimulation = null; } diff --git a/src/main/java/electrosphere/server/datacell/RealmManager.java b/src/main/java/electrosphere/server/datacell/RealmManager.java index 2a0cb919..9a1114ac 100644 --- a/src/main/java/electrosphere/server/datacell/RealmManager.java +++ b/src/main/java/electrosphere/server/datacell/RealmManager.java @@ -209,15 +209,22 @@ public class RealmManager { * Resets the realm manager */ public void reset(){ - for(Realm realm : this.realms){ - if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null){ - realm.getServerWorldData().getServerTerrainManager().closeThreads(); - } - } this.realms.clear(); this.entityToRealmMap.clear(); this.playerToRealmMap.clear(); } + /** + * Closes the realm manager, destroying all resources + */ + public void close(){ + for(Realm realm : this.realms){ + if(realm.getServerWorldData() != null && realm.getServerWorldData().getServerTerrainManager() != null){ + realm.getServerWorldData().getServerTerrainManager().closeThreads(); + } + } + this.reset(); + } + } diff --git a/src/main/java/electrosphere/server/terrain/diskmap/ChunkDiskMap.java b/src/main/java/electrosphere/server/terrain/diskmap/ChunkDiskMap.java index c593c906..30238840 100644 --- a/src/main/java/electrosphere/server/terrain/diskmap/ChunkDiskMap.java +++ b/src/main/java/electrosphere/server/terrain/diskmap/ChunkDiskMap.java @@ -7,7 +7,7 @@ import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.Semaphore; +import java.util.concurrent.locks.ReentrantLock; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterOutputStream; @@ -30,7 +30,7 @@ public class ChunkDiskMap { * Locks the chunk disk map for thread safety */ @Exclude - Semaphore lock = new Semaphore(1); + ReentrantLock lock = new ReentrantLock(); /** * Constructor @@ -90,9 +90,9 @@ public class ChunkDiskMap { * @return True if the map contains the chunk, false otherwise */ public boolean containsTerrainAtPosition(int worldX, int worldY, int worldZ){ - lock.acquireUninterruptibly(); + lock.lock(); boolean rVal = worldPosFileMap.containsKey(getTerrainChunkKey(worldX, worldY, worldZ)); - lock.release(); + lock.unlock(); return rVal; } @@ -104,9 +104,9 @@ public class ChunkDiskMap { * @return True if the map contains the chunk, false otherwise */ public boolean containsFluidAtPosition(int worldX, int worldY, int worldZ){ - lock.acquireUninterruptibly(); + lock.lock(); boolean rVal = worldPosFileMap.containsKey(getFluidChunkKey(worldX, worldY, worldZ)); - lock.release(); + lock.unlock(); return rVal; } @@ -118,7 +118,7 @@ public class ChunkDiskMap { * @return The server terrain chunk if it exists, null otherwise */ public ServerTerrainChunk getTerrainChunk(int worldX, int worldY, int worldZ){ - lock.acquireUninterruptibly(); + lock.lock(); LoggerInterface.loggerEngine.INFO("Load chunk " + worldX + " " + worldY + " " + worldZ); ServerTerrainChunk rVal = null; if(containsTerrainAtPosition(worldX, worldY, worldZ)){ @@ -142,7 +142,7 @@ public class ChunkDiskMap { if(rawData != null){ ByteBuffer buffer = ByteBuffer.wrap(rawData); FloatBuffer floatView = buffer.asFloatBuffer(); - int DIM = ServerTerrainChunk.CHUNK_DIMENSION; + int DIM = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; float[][][] weights = new float[DIM][DIM][DIM]; int[][][] values = new int[DIM][DIM][DIM]; for(int x = 0; x < DIM; x++){ @@ -171,7 +171,7 @@ public class ChunkDiskMap { rVal = new ServerTerrainChunk(worldX, worldY, worldZ, homogenous ? firstType : ChunkData.NOT_HOMOGENOUS, weights, values); } } - lock.release(); + lock.unlock(); return rVal; } @@ -180,7 +180,7 @@ public class ChunkDiskMap { * @param terrainChunk The terrain chunk */ public void saveToDisk(ServerTerrainChunk terrainChunk){ - lock.acquireUninterruptibly(); + lock.lock(); LoggerInterface.loggerEngine.DEBUG("Save to disk: " + terrainChunk.getWorldX() + " " + terrainChunk.getWorldY() + " " + terrainChunk.getWorldZ()); //get the file name for this chunk String fileName = null; @@ -193,7 +193,7 @@ public class ChunkDiskMap { //generate binary for the file float[][][] weights = terrainChunk.getWeights(); int[][][] values = terrainChunk.getValues(); - int DIM = ServerTerrainChunk.CHUNK_DIMENSION; + int DIM = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; ByteBuffer buffer = ByteBuffer.allocate(DIM * DIM * DIM * 4 + DIM * DIM * DIM * 4); FloatBuffer floatView = buffer.asFloatBuffer(); for(int x = 0; x < DIM; x++){ @@ -227,7 +227,7 @@ public class ChunkDiskMap { // TODO Auto-generated catch block e.printStackTrace(); } - lock.release(); + lock.unlock(); } }