remove several usages of concurrent datastructures
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-05-03 17:20:10 -04:00
parent 68294ab636
commit 4458c9e266
10 changed files with 277 additions and 107 deletions

View File

@ -1654,6 +1654,7 @@ Refactor recast pathfinding classes
(05/03/2025) (05/03/2025)
Fix voxel pathfinding logic Fix voxel pathfinding logic
Remove several usages of concurrent datastructures

View File

@ -1,7 +1,8 @@
package electrosphere.client.scene; package electrosphere.client.scene;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.ode4j.ode.DContactGeom; import org.ode4j.ode.DContactGeom;
@ -24,11 +25,11 @@ import electrosphere.logger.LoggerInterface;
public class ClientSceneWrapper { public class ClientSceneWrapper {
//entity id translation between server/client //entity id translation between server/client
Map<Integer,Integer> clientToServerIdMap = new ConcurrentHashMap<Integer,Integer>(); Map<Integer,Integer> clientToServerIdMap = new HashMap<Integer,Integer>();
Map<Integer,Integer> serverToClientIdMap = new ConcurrentHashMap<Integer,Integer>(); Map<Integer,Integer> serverToClientIdMap = new HashMap<Integer,Integer>();
//The list of server IDs that have been deleted //The list of server IDs that have been deleted
Map<Integer,Boolean> deletedServerIds = new ConcurrentHashMap<Integer,Boolean>(); Map<Integer,Boolean> deletedServerIds = new HashMap<Integer,Boolean>();
//The scene backing the wrapper //The scene backing the wrapper
Scene scene; Scene scene;
@ -49,6 +50,11 @@ public class ClientSceneWrapper {
//The hitbox manager //The hitbox manager
HitboxManager hitboxManager; HitboxManager hitboxManager;
/**
* Lock for threadsafing the scene wrapper
*/
ReentrantLock lock = new ReentrantLock();
/** /**
* Constructor * Constructor
* @param scene The scene * @param scene The scene
@ -71,8 +77,10 @@ public class ClientSceneWrapper {
*/ */
public void mapIdToId(int clientId, int serverId){ public void mapIdToId(int clientId, int serverId){
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] MapID: " + clientId + " <===> " + serverId); LoggerInterface.loggerNetworking.DEBUG("[CLIENT] MapID: " + clientId + " <===> " + serverId);
lock.lock();
clientToServerIdMap.put(clientId, serverId); clientToServerIdMap.put(clientId, serverId);
serverToClientIdMap.put(serverId, clientId); serverToClientIdMap.put(serverId, clientId);
lock.unlock();
} }
/** /**
@ -81,11 +89,15 @@ public class ClientSceneWrapper {
* @return The equivalent id on the server, or -1 if no equivalent is found * @return The equivalent id on the server, or -1 if no equivalent is found
*/ */
public int mapClientToServerId(int clientId){ public int mapClientToServerId(int clientId){
lock.lock();
if(clientToServerIdMap.get(clientId) == null){ if(clientToServerIdMap.get(clientId) == null){
LoggerInterface.loggerNetworking.ERROR(new Error("Failed to map client entity " + clientId + " to server entity!")); LoggerInterface.loggerNetworking.ERROR(new Error("Failed to map client entity " + clientId + " to server entity!"));
lock.unlock();
return -1; return -1;
} }
return clientToServerIdMap.get(clientId); int rVal = clientToServerIdMap.get(clientId);
lock.unlock();
return rVal;
} }
/** /**
@ -94,7 +106,10 @@ public class ClientSceneWrapper {
* @return The equivalent id on the client * @return The equivalent id on the client
*/ */
public int mapServerToClientId(int serverId){ public int mapServerToClientId(int serverId){
return serverToClientIdMap.get(serverId); lock.lock();
int rVal = serverToClientIdMap.get(serverId);
lock.unlock();
return rVal;
} }
/** /**
@ -103,7 +118,10 @@ public class ClientSceneWrapper {
* @return true if the map contains that id, false otherwise * @return true if the map contains that id, false otherwise
*/ */
public boolean containsServerId(int serverId){ public boolean containsServerId(int serverId){
return serverToClientIdMap.containsKey(serverId); lock.lock();
boolean rVal = serverToClientIdMap.containsKey(serverId);
lock.unlock();
return rVal;
} }
@ -113,7 +131,10 @@ public class ClientSceneWrapper {
* @return True if the server->client map contains the provided id * @return True if the server->client map contains the provided id
*/ */
public boolean serverToClientMapContainsId(int id){ public boolean serverToClientMapContainsId(int id){
return serverToClientIdMap.containsKey(id); lock.lock();
boolean rVal = serverToClientIdMap.containsKey(id);
lock.unlock();
return rVal;
} }
/** /**
@ -122,7 +143,10 @@ public class ClientSceneWrapper {
* @return true if there's a corresponding server id, false otherwise * @return true if there's a corresponding server id, false otherwise
*/ */
public boolean clientToServerMapContainsId(int id){ public boolean clientToServerMapContainsId(int id){
return clientToServerIdMap.containsKey(id); lock.lock();
boolean rVal = clientToServerIdMap.containsKey(id);
lock.unlock();
return rVal;
} }
/** /**
@ -130,6 +154,7 @@ public class ClientSceneWrapper {
* @param clientEntity The client entity * @param clientEntity The client entity
*/ */
public void deregisterTranslationMapping(Entity clientEntity){ public void deregisterTranslationMapping(Entity clientEntity){
lock.lock();
if(this.clientToServerMapContainsId(clientEntity.getId())){ if(this.clientToServerMapContainsId(clientEntity.getId())){
//remove from client->server map //remove from client->server map
int serverId = clientToServerIdMap.remove(clientEntity.getId()); int serverId = clientToServerIdMap.remove(clientEntity.getId());
@ -138,6 +163,7 @@ public class ClientSceneWrapper {
deletedServerIds.put(serverId,true); deletedServerIds.put(serverId,true);
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Remove scene from client<->server translation layer: " + clientEntity.getId() + "<->" + serverId); LoggerInterface.loggerNetworking.DEBUG("[CLIENT] Remove scene from client<->server translation layer: " + clientEntity.getId() + "<->" + serverId);
} }
lock.unlock();
} }
/** /**
@ -146,7 +172,10 @@ public class ClientSceneWrapper {
* @return true if it was registered at one point and has since been deleted, false otherwise * @return true if it was registered at one point and has since been deleted, false otherwise
*/ */
public boolean hasBeenDeleted(int serverId){ public boolean hasBeenDeleted(int serverId){
return deletedServerIds.containsKey(serverId); lock.lock();
boolean rVal = deletedServerIds.containsKey(serverId);
lock.unlock();
return rVal;
} }
@ -156,22 +185,26 @@ public class ClientSceneWrapper {
* @return The entity in question * @return The entity in question
*/ */
public Entity getEntityFromServerId(int id){ public Entity getEntityFromServerId(int id){
Entity rVal = null;
lock.lock();
if(serverToClientIdMap.containsKey(id)){ if(serverToClientIdMap.containsKey(id)){
int clientId = mapServerToClientId(id); int clientId = mapServerToClientId(id);
return scene.getEntityFromId(clientId); rVal = scene.getEntityFromId(clientId);
} else {
return null;
} }
lock.unlock();
return rVal;
} }
/** /**
* Dumps the status of the network translation layer * Dumps the status of the network translation layer
*/ */
public void dumpTranslationLayerStatus(){ public void dumpTranslationLayerStatus(){
lock.lock();
LoggerInterface.loggerNetworking.WARNING("Client -> Server keys"); LoggerInterface.loggerNetworking.WARNING("Client -> Server keys");
LoggerInterface.loggerNetworking.WARNING(clientToServerIdMap.keySet() + ""); LoggerInterface.loggerNetworking.WARNING(clientToServerIdMap.keySet() + "");
LoggerInterface.loggerNetworking.WARNING("Server -> Client keys"); LoggerInterface.loggerNetworking.WARNING("Server -> Client keys");
LoggerInterface.loggerNetworking.WARNING(serverToClientIdMap.keySet() + ""); LoggerInterface.loggerNetworking.WARNING(serverToClientIdMap.keySet() + "");
lock.unlock();
} }
/** /**
@ -179,6 +212,7 @@ public class ClientSceneWrapper {
* @param id The id * @param id The id
*/ */
public void dumpIdData(int id){ public void dumpIdData(int id){
lock.lock();
LoggerInterface.loggerNetworking.WARNING("Offending ID " + id); LoggerInterface.loggerNetworking.WARNING("Offending ID " + id);
LoggerInterface.loggerNetworking.WARNING("Client->Server Map contains? " + clientToServerIdMap.containsKey(id)); LoggerInterface.loggerNetworking.WARNING("Client->Server Map contains? " + clientToServerIdMap.containsKey(id));
LoggerInterface.loggerNetworking.WARNING("Server->Client Map contains? " + serverToClientIdMap.containsKey(id)); LoggerInterface.loggerNetworking.WARNING("Server->Client Map contains? " + serverToClientIdMap.containsKey(id));
@ -188,6 +222,7 @@ public class ClientSceneWrapper {
if(serverToClientIdMap.containsKey(id)){ if(serverToClientIdMap.containsKey(id)){
LoggerInterface.loggerNetworking.WARNING("Server->Client Map entity: " + serverToClientIdMap.get(id)); LoggerInterface.loggerNetworking.WARNING("Server->Client Map entity: " + serverToClientIdMap.get(id));
} }
lock.unlock();
} }
/** /**

View File

@ -24,12 +24,11 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import org.lwjgl.assimp.AIScene; import org.lwjgl.assimp.AIScene;
@ -39,44 +38,48 @@ import org.ode4j.ode.DBody;
* Manages all assets loaded into the engine including initially loading and destructing * Manages all assets loaded into the engine including initially loading and destructing
*/ */
public class AssetManager { public class AssetManager {
Map<String,Model> modelsLoadedIntoMemory = new ConcurrentHashMap<String,Model>();
List<String> modelsInQueue = new CopyOnWriteArrayList<String>();
List<String> modelsInDeleteQueue = new CopyOnWriteArrayList<String>();
List<MeshShaderOverride> shaderOverrides = new CopyOnWriteArrayList<MeshShaderOverride>();
Map<String,Texture> texturesLoadedIntoMemory = new ConcurrentHashMap<String,Texture>();
List<String> texturesInQueue = new CopyOnWriteArrayList<String>();
List<String> texturesInDeleteQueue = new CopyOnWriteArrayList<String>();
Map<String,AudioBuffer> audioLoadedIntoMemory = new ConcurrentHashMap<String,AudioBuffer>();
List<String> audioInQueue = new CopyOnWriteArrayList<String>();
Map<String,VisualShader> shadersLoadedIntoMemory = new ConcurrentHashMap<String,VisualShader>(); /**
List<ActorShaderMask> shadersInQueue = new CopyOnWriteArrayList<ActorShaderMask>(); * Lock for thread-safing the work
*/
ReentrantLock lock = new ReentrantLock();
Map<String,Model> modelsLoadedIntoMemory = new HashMap<String,Model>();
List<String> modelsInQueue = new LinkedList<String>();
List<String> modelsInDeleteQueue = new LinkedList<String>();
List<MeshShaderOverride> shaderOverrides = new LinkedList<MeshShaderOverride>();
Map<String,Texture> texturesLoadedIntoMemory = new HashMap<String,Texture>();
List<String> texturesInQueue = new LinkedList<String>();
List<String> texturesInDeleteQueue = new LinkedList<String>();
Map<String,AudioBuffer> audioLoadedIntoMemory = new HashMap<String,AudioBuffer>();
List<String> audioInQueue = new LinkedList<String>();
Map<String,VisualShader> shadersLoadedIntoMemory = new HashMap<String,VisualShader>();
List<ActorShaderMask> shadersInQueue = new LinkedList<ActorShaderMask>();
// //
//Compute shader related //Compute shader related
// //
Map<String,ComputeShader> computeShadersLoadedIntoMemory = new ConcurrentHashMap<String,ComputeShader>(); Map<String,ComputeShader> computeShadersLoadedIntoMemory = new HashMap<String,ComputeShader>();
List<String> computeShadersInQueue = new CopyOnWriteArrayList<String>(); List<String> computeShadersInQueue = new LinkedList<String>();
Map<String,DBody> physicsMeshesLoadedIntoMemory = new ConcurrentHashMap<String,DBody>(); Map<String,DBody> physicsMeshesLoadedIntoMemory = new HashMap<String,DBody>();
List<PhysicsMeshQueueItem> physicsMeshesToLoad = new CopyOnWriteArrayList<PhysicsMeshQueueItem>(); List<PhysicsMeshQueueItem> physicsMeshesToLoad = new LinkedList<PhysicsMeshQueueItem>();
Map<String,PoseModel> poseModelsLoadedIntoMemory = new ConcurrentHashMap<String,PoseModel>(); Map<String,PoseModel> poseModelsLoadedIntoMemory = new HashMap<String,PoseModel>();
List<String> poseModelsInQueue = new CopyOnWriteArrayList<String>(); List<String> poseModelsInQueue = new LinkedList<String>();
List<String> poseModelsInDeleteQueue = new CopyOnWriteArrayList<String>(); List<String> poseModelsInDeleteQueue = new LinkedList<String>();
//A queue of homogenous buffers to allocate this render frame //A queue of homogenous buffers to allocate this render frame
List<HomogenousUniformBuffer> homogenousBufferAllocationQueue = new CopyOnWriteArrayList<HomogenousUniformBuffer>(); List<HomogenousUniformBuffer> homogenousBufferAllocationQueue = new LinkedList<HomogenousUniformBuffer>();
//A queue of homogenous buffers to allocate this render frame //A queue of homogenous buffers to allocate this render frame
List<HomogenousInstancedArray> instanceArrayBufferAllocationQueue = new CopyOnWriteArrayList<HomogenousInstancedArray>(); List<HomogenousInstancedArray> instanceArrayBufferAllocationQueue = new LinkedList<HomogenousInstancedArray>();
//assets queued to be loaded //assets queued to be loaded
ReentrantLock queuedAssetLock = new ReentrantLock();
List<QueuedAsset<?>> queuedAssets = new LinkedList<QueuedAsset<?>>(); List<QueuedAsset<?>> queuedAssets = new LinkedList<QueuedAsset<?>>();
/** /**
@ -98,8 +101,8 @@ public class AssetManager {
//models //models
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load models"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load models");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load Models"); Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load Models");
lock.lock();
for(String currentPath : modelsInQueue){ for(String currentPath : modelsInQueue){
modelsInQueue.remove(currentPath);
AIScene aiScene = ModelLoader.loadAIScene(currentPath); AIScene aiScene = ModelLoader.loadAIScene(currentPath);
TextureMap textureMap = null; TextureMap textureMap = null;
if(this.getLocalTextureMapPath(currentPath) != null){ if(this.getLocalTextureMapPath(currentPath) != null){
@ -119,43 +122,43 @@ public class AssetManager {
} }
} }
} }
modelsInQueue.clear();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//textures from disk to gpu //textures from disk to gpu
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load textures"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load textures");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load textures"); Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load textures");
for(String currentPath : texturesInQueue){ for(String currentPath : texturesInQueue){
texturesInQueue.remove(currentPath);
Texture tex = new Texture(Globals.renderingEngine.getOpenGLState(), currentPath); Texture tex = new Texture(Globals.renderingEngine.getOpenGLState(), currentPath);
texturesLoadedIntoMemory.put(currentPath, tex); texturesLoadedIntoMemory.put(currentPath, tex);
} }
texturesInQueue.clear();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//audio from disk //audio from disk
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load audio"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load audio");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load audio"); Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load audio");
if(Globals.audioEngine != null && Globals.audioEngine.initialized()){ if(Globals.audioEngine != null && Globals.audioEngine.initialized()){
for(String currentPath : audioInQueue){ for(String currentPath : audioInQueue){
audioInQueue.remove(currentPath);
audioLoadedIntoMemory.put(currentPath, new AudioBuffer(currentPath)); audioLoadedIntoMemory.put(currentPath, new AudioBuffer(currentPath));
} }
audioInQueue.clear();
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//shaders //shaders
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load visual shaders"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load visual shaders");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load visual shaders"); Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load visual shaders");
for(ActorShaderMask currentShader : shadersInQueue){ for(ActorShaderMask currentShader : shadersInQueue){
shadersInQueue.remove(currentShader);
String key = getShaderKey(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath()); String key = getShaderKey(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath());
shadersLoadedIntoMemory.put( shadersLoadedIntoMemory.put(
key, key,
VisualShader.loadSpecificShader(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath()) VisualShader.loadSpecificShader(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath())
); );
} }
shadersInQueue.clear();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//compute shaders //compute shaders
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load compute shaders"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load compute shaders");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load compute shaders"); Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load compute shaders");
for(String computePath : computeShadersInQueue){ for(String computePath : computeShadersInQueue){
computeShadersInQueue.remove(computePath);
String key = getComputeShaderKey(computePath); String key = getComputeShaderKey(computePath);
try { try {
computeShadersLoadedIntoMemory.put( computeShadersLoadedIntoMemory.put(
@ -166,20 +169,20 @@ public class AssetManager {
e.printStackTrace(); e.printStackTrace();
} }
} }
computeShadersInQueue.clear();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//pose models //pose models
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load pose models"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load pose models");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load pose models"); Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load pose models");
for(String currentPath: poseModelsInQueue){ for(String currentPath: poseModelsInQueue){
poseModelsInQueue.remove(currentPath);
AIScene scene = ModelLoader.loadAIScene(currentPath); AIScene scene = ModelLoader.loadAIScene(currentPath);
poseModelsLoadedIntoMemory.put(currentPath, new PoseModel(currentPath, scene)); poseModelsLoadedIntoMemory.put(currentPath, new PoseModel(currentPath, scene));
} }
poseModelsInQueue.clear();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//queued assets //queued assets
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load queued assets"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load queued assets");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load queued assets"); Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load queued assets");
queuedAssetLock.lock();
if(queuedAssets.size() > MAX_ASSETS_PER_FRAME){ if(queuedAssets.size() > MAX_ASSETS_PER_FRAME){
for(int i = 0; i < MAX_ASSETS_PER_FRAME; i++){ for(int i = 0; i < MAX_ASSETS_PER_FRAME; i++){
QueuedAsset<?> queuedAsset = queuedAssets.remove(0); QueuedAsset<?> queuedAsset = queuedAssets.remove(0);
@ -201,7 +204,6 @@ public class AssetManager {
} }
queuedAssets.clear(); queuedAssets.clear();
} }
queuedAssetLock.unlock();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
//allocate homogenous buffers //allocate homogenous buffers
@ -219,6 +221,8 @@ public class AssetManager {
//override meshes //override meshes
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Override meshes"); LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Override meshes");
this.performMeshOverrides(); this.performMeshOverrides();
lock.unlock();
} }
@ -228,6 +232,7 @@ public class AssetManager {
public void updateAsset(String path){ public void updateAsset(String path){
LoggerInterface.loggerEngine.DEBUG("AssetManager - updateAsset"); LoggerInterface.loggerEngine.DEBUG("AssetManager - updateAsset");
//models //models
lock.lock();
if(modelsLoadedIntoMemory.containsKey(path)){ if(modelsLoadedIntoMemory.containsKey(path)){
this.queueModelForDeletion(path); this.queueModelForDeletion(path);
this.deleteModelsInDeleteQueue(); this.deleteModelsInDeleteQueue();
@ -254,15 +259,18 @@ public class AssetManager {
if(computeShadersLoadedIntoMemory.containsKey(path)){ if(computeShadersLoadedIntoMemory.containsKey(path)){
throw new Error("Unhandled asset type! (Shader - Compute)"); throw new Error("Unhandled asset type! (Shader - Compute)");
} }
lock.unlock();
} }
/** /**
* Handles the delete queues * Handles the delete queues
*/ */
public void handleDeleteQueue(){ public void handleDeleteQueue(){
lock.lock();
this.deleteModelsInDeleteQueue(); this.deleteModelsInDeleteQueue();
this.deletePoseModelsInDeleteQueue(); this.deletePoseModelsInDeleteQueue();
this.deleteTexturesInDeleteQueue(); this.deleteTexturesInDeleteQueue();
lock.unlock();
} }
@ -277,16 +285,20 @@ public class AssetManager {
// //
public void addModelPathToQueue(String path){ public void addModelPathToQueue(String path){
lock.lock();
if(!modelsInQueue.contains(path) && !modelsLoadedIntoMemory.containsKey(path)){ if(!modelsInQueue.contains(path) && !modelsLoadedIntoMemory.containsKey(path)){
modelsInQueue.add(path); modelsInQueue.add(path);
} }
lock.unlock();
} }
public Model fetchModel(String path){ public Model fetchModel(String path){
Model rVal = null; Model rVal = null;
lock.lock();
if(modelsLoadedIntoMemory.containsKey(path)){ if(modelsLoadedIntoMemory.containsKey(path)){
rVal = modelsLoadedIntoMemory.get(path); rVal = modelsLoadedIntoMemory.get(path);
} }
lock.unlock();
return rVal; return rVal;
} }
@ -295,7 +307,9 @@ public class AssetManager {
* @param modelPath The path to the model * @param modelPath The path to the model
*/ */
public void queueModelForDeletion(String modelPath){ public void queueModelForDeletion(String modelPath){
lock.lock();
modelsInDeleteQueue.add(modelPath); modelsInDeleteQueue.add(modelPath);
lock.unlock();
} }
/** /**
@ -306,7 +320,9 @@ public class AssetManager {
String rVal; String rVal;
UUID newUUID = UUID.randomUUID(); UUID newUUID = UUID.randomUUID();
rVal = newUUID.toString(); rVal = newUUID.toString();
lock.lock();
modelsLoadedIntoMemory.put(rVal,m); modelsLoadedIntoMemory.put(rVal,m);
lock.unlock();
return rVal; return rVal;
} }
@ -317,20 +333,27 @@ public class AssetManager {
* @param path The path to register the model to * @param path The path to register the model to
*/ */
public void registerModelWithPath(Model m, String path){ public void registerModelWithPath(Model m, String path){
lock.lock();
modelsLoadedIntoMemory.put(path, m); modelsLoadedIntoMemory.put(path, m);
lock.unlock();
} }
public void deregisterModelPath(String path){ public void deregisterModelPath(String path){
lock.lock();
modelsLoadedIntoMemory.remove(path); modelsLoadedIntoMemory.remove(path);
lock.unlock();
} }
public void queueOverrideMeshShader(String modelName, String meshName, String vertPath, String fragPath){ public void queueOverrideMeshShader(String modelName, String meshName, String vertPath, String fragPath){
lock.lock();
MeshShaderOverride override = new MeshShaderOverride(modelName,meshName,vertPath,fragPath); MeshShaderOverride override = new MeshShaderOverride(modelName,meshName,vertPath,fragPath);
shaderOverrides.add(override); shaderOverrides.add(override);
lock.unlock();
} }
public void performMeshOverrides(){ public void performMeshOverrides(){
List<MeshShaderOverride> toRemove = new LinkedList<MeshShaderOverride>(); List<MeshShaderOverride> toRemove = new LinkedList<MeshShaderOverride>();
lock.lock();
for(MeshShaderOverride shaderOverride : shaderOverrides){ for(MeshShaderOverride shaderOverride : shaderOverrides){
Model model = null; Model model = null;
if((model = fetchModel(shaderOverride.modelName)) != null){ if((model = fetchModel(shaderOverride.modelName)) != null){
@ -345,25 +368,28 @@ public class AssetManager {
for(MeshShaderOverride shaderOverride : toRemove){ for(MeshShaderOverride shaderOverride : toRemove){
shaderOverrides.remove(shaderOverride); shaderOverrides.remove(shaderOverride);
} }
lock.unlock();
} }
/** /**
* Nuclear function, reloads all shaders loaded into memory * Nuclear function, reloads all shaders loaded into memory
*/ */
public void forceReloadAllModels(){ public void forceReloadAllModels(){
lock.lock();
for(String modelKey : modelsLoadedIntoMemory.keySet()){ for(String modelKey : modelsLoadedIntoMemory.keySet()){
if(modelKey.contains("Models")){ if(modelKey.contains("Models")){
modelsInQueue.add(modelKey); modelsInQueue.add(modelKey);
modelsLoadedIntoMemory.remove(modelKey); modelsLoadedIntoMemory.remove(modelKey);
} }
} }
// modelsLoadedIntoMemory.clear(); lock.unlock();
} }
/** /**
* Deletes all models in the delete queue * Deletes all models in the delete queue
*/ */
public void deleteModelsInDeleteQueue(){ public void deleteModelsInDeleteQueue(){
lock.lock();
for(String modelPath : modelsInDeleteQueue){ for(String modelPath : modelsInDeleteQueue){
Model model = this.fetchModel(modelPath); Model model = this.fetchModel(modelPath);
if(model != null){ if(model != null){
@ -371,6 +397,7 @@ public class AssetManager {
} }
this.modelsLoadedIntoMemory.remove(modelPath); this.modelsLoadedIntoMemory.remove(modelPath);
} }
lock.unlock();
} }
@ -388,9 +415,11 @@ public class AssetManager {
* @param path The path to load * @param path The path to load
*/ */
public void addPoseModelPathToQueue(String path){ public void addPoseModelPathToQueue(String path){
lock.lock();
if(!poseModelsInQueue.contains(path) && !poseModelsLoadedIntoMemory.containsKey(path)){ if(!poseModelsInQueue.contains(path) && !poseModelsLoadedIntoMemory.containsKey(path)){
poseModelsInQueue.add(path); poseModelsInQueue.add(path);
} }
lock.unlock();
} }
/** /**
@ -400,9 +429,11 @@ public class AssetManager {
*/ */
public PoseModel fetchPoseModel(String path){ public PoseModel fetchPoseModel(String path){
PoseModel rVal = null; PoseModel rVal = null;
lock.lock();
if(poseModelsLoadedIntoMemory.containsKey(path)){ if(poseModelsLoadedIntoMemory.containsKey(path)){
rVal = poseModelsLoadedIntoMemory.get(path); rVal = poseModelsLoadedIntoMemory.get(path);
} }
lock.unlock();
return rVal; return rVal;
} }
@ -413,7 +444,9 @@ public class AssetManager {
* @param path The path to register the pose model to * @param path The path to register the pose model to
*/ */
public void registerPoseModelWithPath(PoseModel m, String path){ public void registerPoseModelWithPath(PoseModel m, String path){
lock.lock();
poseModelsLoadedIntoMemory.put(path, m); poseModelsLoadedIntoMemory.put(path, m);
lock.unlock();
} }
/** /**
@ -421,13 +454,16 @@ public class AssetManager {
* @param modelPath The path to the pose model * @param modelPath The path to the pose model
*/ */
public void queuePoseModelForDeletion(String modelPath){ public void queuePoseModelForDeletion(String modelPath){
lock.lock();
poseModelsInDeleteQueue.add(modelPath); poseModelsInDeleteQueue.add(modelPath);
lock.unlock();
} }
/** /**
* Deletes all pose models in the delete queue * Deletes all pose models in the delete queue
*/ */
public void deletePoseModelsInDeleteQueue(){ public void deletePoseModelsInDeleteQueue(){
lock.lock();
for(String modelPath : poseModelsInDeleteQueue){ for(String modelPath : poseModelsInDeleteQueue){
PoseModel poseModel = this.fetchPoseModel(modelPath); PoseModel poseModel = this.fetchPoseModel(modelPath);
if(poseModel != null){ if(poseModel != null){
@ -435,6 +471,7 @@ public class AssetManager {
} }
this.poseModelsLoadedIntoMemory.remove(modelPath); this.poseModelsLoadedIntoMemory.remove(modelPath);
} }
lock.unlock();
} }
@ -451,9 +488,11 @@ public class AssetManager {
public void addTexturePathtoQueue(String path){ public void addTexturePathtoQueue(String path){
lock.lock();
if(!texturesInQueue.contains(path) && !texturesLoadedIntoMemory.containsKey(path)){ if(!texturesInQueue.contains(path) && !texturesLoadedIntoMemory.containsKey(path)){
texturesInQueue.add(path); texturesInQueue.add(path);
} }
lock.unlock();
} }
/** /**
@ -461,14 +500,18 @@ public class AssetManager {
* @param texturePath The path to the texture * @param texturePath The path to the texture
*/ */
public void queueTextureForDeletion(String texturePath){ public void queueTextureForDeletion(String texturePath){
lock.lock();
texturesInDeleteQueue.add(texturePath); texturesInDeleteQueue.add(texturePath);
lock.unlock();
} }
public Texture fetchTexture(String path){ public Texture fetchTexture(String path){
Texture rVal = null; Texture rVal = null;
lock.lock();
if(texturesLoadedIntoMemory.containsKey(path)){ if(texturesLoadedIntoMemory.containsKey(path)){
rVal = texturesLoadedIntoMemory.get(path); rVal = texturesLoadedIntoMemory.get(path);
} }
lock.unlock();
return rVal; return rVal;
} }
@ -476,7 +519,9 @@ public class AssetManager {
String rVal; String rVal;
UUID newUUID = UUID.randomUUID(); UUID newUUID = UUID.randomUUID();
rVal = newUUID.toString(); rVal = newUUID.toString();
lock.lock();
texturesLoadedIntoMemory.put(rVal,t); texturesLoadedIntoMemory.put(rVal,t);
lock.unlock();
return rVal; return rVal;
} }
@ -486,11 +531,16 @@ public class AssetManager {
* @param path The path * @param path The path
*/ */
public void registerTextureToPath(Texture t, String path){ public void registerTextureToPath(Texture t, String path){
lock.lock();
texturesLoadedIntoMemory.put(path,t); texturesLoadedIntoMemory.put(path,t);
lock.unlock();
} }
public boolean hasLoadedTexture(String path){ public boolean hasLoadedTexture(String path){
return texturesLoadedIntoMemory.containsKey(path); lock.lock();
boolean rVal = texturesLoadedIntoMemory.containsKey(path);
lock.unlock();
return rVal;
} }
/** /**
@ -498,6 +548,7 @@ public class AssetManager {
* @param modelPath The model's path * @param modelPath The model's path
*/ */
private String getLocalTextureMapPath(String modelPath){ private String getLocalTextureMapPath(String modelPath){
lock.lock();
File modelFile = FileUtils.getAssetFile(modelPath); File modelFile = FileUtils.getAssetFile(modelPath);
File containingDirectory = modelFile.getParentFile(); File containingDirectory = modelFile.getParentFile();
File[] children = containingDirectory.listFiles(); File[] children = containingDirectory.listFiles();
@ -506,10 +557,12 @@ public class AssetManager {
if(child.getName().equals("texturemap.json")){ if(child.getName().equals("texturemap.json")){
String rVal = child.getPath(); String rVal = child.getPath();
String fixed = rVal.replace(".\\assets", "").replace("./assets", ""); String fixed = rVal.replace(".\\assets", "").replace("./assets", "");
lock.unlock();
return fixed; return fixed;
} }
} }
} }
lock.unlock();
return null; return null;
} }
@ -517,6 +570,7 @@ public class AssetManager {
* Deletes all textures in the delete queue * Deletes all textures in the delete queue
*/ */
public void deleteTexturesInDeleteQueue(){ public void deleteTexturesInDeleteQueue(){
lock.lock();
for(String texturePath : texturesInDeleteQueue){ for(String texturePath : texturesInDeleteQueue){
Texture texture = this.fetchTexture(texturePath); Texture texture = this.fetchTexture(texturePath);
if(texture != null){ if(texture != null){
@ -524,6 +578,7 @@ public class AssetManager {
} }
this.texturesLoadedIntoMemory.remove(texturePath); this.texturesLoadedIntoMemory.remove(texturePath);
} }
lock.unlock();
} }
@ -539,13 +594,16 @@ public class AssetManager {
// //
public void addAudioPathToQueue(String path){ public void addAudioPathToQueue(String path){
lock.lock();
String sanitizedPath = FileUtils.sanitizeFilePath(path); String sanitizedPath = FileUtils.sanitizeFilePath(path);
if(!audioInQueue.contains(sanitizedPath) && !audioLoadedIntoMemory.containsKey(sanitizedPath)){ if(!audioInQueue.contains(sanitizedPath) && !audioLoadedIntoMemory.containsKey(sanitizedPath)){
audioInQueue.add(sanitizedPath); audioInQueue.add(sanitizedPath);
} }
lock.unlock();
} }
public AudioBuffer fetchAudio(String path){ public AudioBuffer fetchAudio(String path){
lock.lock();
AudioBuffer rVal = null; AudioBuffer rVal = null;
String sanitizedPath = FileUtils.sanitizeFilePath(path); String sanitizedPath = FileUtils.sanitizeFilePath(path);
if(audioLoadedIntoMemory.containsKey(sanitizedPath)){ if(audioLoadedIntoMemory.containsKey(sanitizedPath)){
@ -553,6 +611,7 @@ public class AssetManager {
} else { } else {
LoggerInterface.loggerAudio.WARNING("Failed to find audio " + sanitizedPath); LoggerInterface.loggerAudio.WARNING("Failed to find audio " + sanitizedPath);
} }
lock.unlock();
return rVal; return rVal;
} }
@ -561,7 +620,10 @@ public class AssetManager {
* @return The collection of all audio buffers * @return The collection of all audio buffers
*/ */
public Collection<AudioBuffer> getAllAudio(){ public Collection<AudioBuffer> getAllAudio(){
return Collections.unmodifiableCollection(this.audioLoadedIntoMemory.values()); lock.lock();
Collection<AudioBuffer> rVal = Collections.unmodifiableCollection(this.audioLoadedIntoMemory.values());
lock.unlock();
return rVal;
} }
@ -575,15 +637,19 @@ public class AssetManager {
//SHADERS //SHADERS
// //
public void addShaderToQueue(String vertexShader, String fragmentShader){ public void addShaderToQueue(String vertexShader, String fragmentShader){
lock.lock();
shadersInQueue.add(new ActorShaderMask("","",vertexShader,fragmentShader)); shadersInQueue.add(new ActorShaderMask("","",vertexShader,fragmentShader));
lock.unlock();
} }
public VisualShader fetchShader(String vertexPath, String fragmentPath){ public VisualShader fetchShader(String vertexPath, String fragmentPath){
lock.lock();
String path = getShaderKey(vertexPath,fragmentPath); String path = getShaderKey(vertexPath,fragmentPath);
VisualShader rVal = null; VisualShader rVal = null;
if(shadersLoadedIntoMemory.containsKey(path)){ if(shadersLoadedIntoMemory.containsKey(path)){
rVal = shadersLoadedIntoMemory.get(path); rVal = shadersLoadedIntoMemory.get(path);
} }
lock.unlock();
return rVal; return rVal;
} }
@ -595,11 +661,13 @@ public class AssetManager {
* Nuclear function, reloads all shaders loaded into memory * Nuclear function, reloads all shaders loaded into memory
*/ */
public void forceReloadAllShaders(){ public void forceReloadAllShaders(){
lock.lock();
for(String shaderKey : shadersLoadedIntoMemory.keySet()){ for(String shaderKey : shadersLoadedIntoMemory.keySet()){
String shaderPaths[] = shaderKey.split("-"); String shaderPaths[] = shaderKey.split("-");
shadersInQueue.add(new ActorShaderMask("","",shaderPaths[0],shaderPaths[1])); shadersInQueue.add(new ActorShaderMask("","",shaderPaths[0],shaderPaths[1]));
} }
shadersLoadedIntoMemory.clear(); shadersLoadedIntoMemory.clear();
lock.unlock();
} }
// //
@ -610,7 +678,9 @@ public class AssetManager {
* @param computePath The path to the source code for the shader * @param computePath The path to the source code for the shader
*/ */
public void addComputeShaderToQueue(String computePath){ public void addComputeShaderToQueue(String computePath){
lock.lock();
computeShadersInQueue.add(getComputeShaderKey(computePath)); computeShadersInQueue.add(getComputeShaderKey(computePath));
lock.unlock();
} }
/** /**
@ -619,11 +689,13 @@ public class AssetManager {
* @return The compute shader if it exists, null otherwise * @return The compute shader if it exists, null otherwise
*/ */
public ComputeShader fetchComputeShader(String computePath){ public ComputeShader fetchComputeShader(String computePath){
lock.lock();
String key = getComputeShaderKey(computePath); String key = getComputeShaderKey(computePath);
ComputeShader rVal = null; ComputeShader rVal = null;
if(computeShadersLoadedIntoMemory.containsKey(key)){ if(computeShadersLoadedIntoMemory.containsKey(key)){
rVal = computeShadersLoadedIntoMemory.get(key); rVal = computeShadersLoadedIntoMemory.get(key);
} }
lock.unlock();
return rVal; return rVal;
} }
@ -643,6 +715,7 @@ public class AssetManager {
//COLLISION MESH //COLLISION MESH
// //
public void addCollisionMeshToQueue(PhysicsMeshQueueItem physicsMeshQueueItem){ public void addCollisionMeshToQueue(PhysicsMeshQueueItem physicsMeshQueueItem){
lock.lock();
if( if(
!physicsMeshesToLoad.contains(physicsMeshQueueItem) && !physicsMeshesToLoad.contains(physicsMeshQueueItem) &&
!physicsMeshesLoadedIntoMemory.containsKey(getCollisionMeshMapKey( !physicsMeshesLoadedIntoMemory.containsKey(getCollisionMeshMapKey(
@ -651,10 +724,14 @@ public class AssetManager {
))){ ))){
physicsMeshesToLoad.add(physicsMeshQueueItem); physicsMeshesToLoad.add(physicsMeshQueueItem);
} }
lock.unlock();
} }
public DBody fetchCollisionObject(CollisionEngine collisionEngine, String path){ public DBody fetchCollisionObject(CollisionEngine collisionEngine, String path){
return physicsMeshesLoadedIntoMemory.get(getCollisionMeshMapKey(collisionEngine,path)); lock.lock();
DBody rVal = physicsMeshesLoadedIntoMemory.get(getCollisionMeshMapKey(collisionEngine,path));
lock.unlock();
return rVal;
} }
/** /**
@ -675,10 +752,12 @@ public class AssetManager {
* Allocates all uniform buffers in queue * Allocates all uniform buffers in queue
*/ */
public void allocateHomogenousBuffers(){ public void allocateHomogenousBuffers(){
lock.lock();
for(HomogenousUniformBuffer buffer : homogenousBufferAllocationQueue){ for(HomogenousUniformBuffer buffer : homogenousBufferAllocationQueue){
buffer.allocate(); buffer.allocate();
} }
homogenousBufferAllocationQueue.clear(); homogenousBufferAllocationQueue.clear();
lock.unlock();
} }
/** /**
@ -686,7 +765,9 @@ public class AssetManager {
* @param buffer The buffer * @param buffer The buffer
*/ */
public void addHomogenousBufferToQueue(HomogenousUniformBuffer buffer){ public void addHomogenousBufferToQueue(HomogenousUniformBuffer buffer){
lock.lock();
homogenousBufferAllocationQueue.add(buffer); homogenousBufferAllocationQueue.add(buffer);
lock.unlock();
} }
@ -697,10 +778,12 @@ public class AssetManager {
* Allocates all instance array buffers in queue * Allocates all instance array buffers in queue
*/ */
public void allocateInstanceArrayBuffers(){ public void allocateInstanceArrayBuffers(){
lock.lock();
for(HomogenousInstancedArray buffer : instanceArrayBufferAllocationQueue){ for(HomogenousInstancedArray buffer : instanceArrayBufferAllocationQueue){
buffer.allocate(); buffer.allocate();
} }
instanceArrayBufferAllocationQueue.clear(); instanceArrayBufferAllocationQueue.clear();
lock.unlock();
} }
/** /**
@ -708,7 +791,9 @@ public class AssetManager {
* @param buffer The buffer * @param buffer The buffer
*/ */
public void addInstanceArrayBufferToQueue(HomogenousInstancedArray buffer){ public void addInstanceArrayBufferToQueue(HomogenousInstancedArray buffer){
lock.lock();
instanceArrayBufferAllocationQueue.add(buffer); instanceArrayBufferAllocationQueue.add(buffer);
lock.unlock();
} }
@ -720,7 +805,7 @@ public class AssetManager {
* @param asset the asset * @param asset the asset
*/ */
public String queuedAsset(QueuedAsset<?> asset){ public String queuedAsset(QueuedAsset<?> asset){
queuedAssetLock.lock(); lock.lock();
this.queuedAssets.add(asset); this.queuedAssets.add(asset);
//promise a specific string for this asset //promise a specific string for this asset
@ -740,7 +825,7 @@ public class AssetManager {
asset.setPromisedPath(promisedPath); asset.setPromisedPath(promisedPath);
} }
queuedAssetLock.unlock(); lock.unlock();
return promisedPath; return promisedPath;
} }

View File

@ -1,10 +1,10 @@
package electrosphere.engine.signal; package electrosphere.engine.signal;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.Semaphore;
import electrosphere.engine.service.Service; import electrosphere.engine.service.Service;
import electrosphere.engine.signal.Signal.SignalType; import electrosphere.engine.signal.Signal.SignalType;
@ -21,16 +21,16 @@ public class SignalSystem implements Service {
Map<SignalType,Set<SignalService>> typeServiceMap; Map<SignalType,Set<SignalService>> typeServiceMap;
/** /**
* The semaphore for thread-safing the system * The lock for thread-safing the system
*/ */
Semaphore systemLock; ReentrantLock systemLock;
/** /**
* Initializes the signal system * Initializes the signal system
*/ */
public void init(){ public void init(){
typeServiceMap = new ConcurrentHashMap<SignalType,Set<SignalService>>(); typeServiceMap = new HashMap<SignalType,Set<SignalService>>();
systemLock = new Semaphore(1); systemLock = new ReentrantLock();
} }
/** /**
@ -52,7 +52,7 @@ public class SignalSystem implements Service {
* @param service The service to associate with that signal type * @param service The service to associate with that signal type
*/ */
public void registerService(SignalService service){ public void registerService(SignalService service){
systemLock.acquireUninterruptibly(); systemLock.lock();
LoggerInterface.loggerEngine.DEBUG("[SignalSystem] Register signal service " + service.getName()); LoggerInterface.loggerEngine.DEBUG("[SignalSystem] Register signal service " + service.getName());
for(SignalType signalType : service.getSubscriptionTargets()){ for(SignalType signalType : service.getSubscriptionTargets()){
if(typeServiceMap.containsKey(signalType)){ if(typeServiceMap.containsKey(signalType)){
@ -66,7 +66,7 @@ public class SignalSystem implements Service {
this.typeServiceMap.put(signalType, services); this.typeServiceMap.put(signalType, services);
} }
} }
systemLock.release(); systemLock.unlock();
} }
/** /**
@ -75,7 +75,7 @@ public class SignalSystem implements Service {
* @param service The service to associate with that signal type * @param service The service to associate with that signal type
*/ */
public void registerServiceToSignal(SignalType signalType, SignalService service){ public void registerServiceToSignal(SignalType signalType, SignalService service){
systemLock.acquireUninterruptibly(); systemLock.lock();
LoggerInterface.loggerEngine.DEBUG("[SignalSystem] Register signal service " + service.getName()); LoggerInterface.loggerEngine.DEBUG("[SignalSystem] Register signal service " + service.getName());
if(typeServiceMap.containsKey(signalType)){ if(typeServiceMap.containsKey(signalType)){
Set<SignalService> services = this.typeServiceMap.get(signalType); Set<SignalService> services = this.typeServiceMap.get(signalType);
@ -87,7 +87,7 @@ public class SignalSystem implements Service {
services.add(service); services.add(service);
this.typeServiceMap.put(signalType, services); this.typeServiceMap.put(signalType, services);
} }
systemLock.release(); systemLock.unlock();
} }
/** /**
@ -96,7 +96,7 @@ public class SignalSystem implements Service {
* @param service The signal service to unassociate from that signal type * @param service The signal service to unassociate from that signal type
*/ */
public void deregisterServiceToSignal(SignalType signalType, SignalService service){ public void deregisterServiceToSignal(SignalType signalType, SignalService service){
systemLock.acquireUninterruptibly(); systemLock.lock();
LoggerInterface.loggerEngine.DEBUG("[SignalSystem] Deregister signal service " + service.getName()); LoggerInterface.loggerEngine.DEBUG("[SignalSystem] Deregister signal service " + service.getName());
if(typeServiceMap.containsKey(signalType)){ if(typeServiceMap.containsKey(signalType)){
Set<SignalService> services = this.typeServiceMap.get(signalType); Set<SignalService> services = this.typeServiceMap.get(signalType);
@ -104,7 +104,7 @@ public class SignalSystem implements Service {
} else { } else {
//there are no services mapped to this signal type //there are no services mapped to this signal type
} }
systemLock.release(); systemLock.unlock();
} }
/** /**
@ -113,7 +113,7 @@ public class SignalSystem implements Service {
* @param data The data associated with the signal * @param data The data associated with the signal
*/ */
public void post(SignalType type, Object data){ public void post(SignalType type, Object data){
systemLock.acquireUninterruptibly(); systemLock.lock();
if(typeServiceMap.containsKey(type)){ if(typeServiceMap.containsKey(type)){
LoggerInterface.loggerEngine.DEBUG("[SignalSystem] Post signal " + type); LoggerInterface.loggerEngine.DEBUG("[SignalSystem] Post signal " + type);
Signal signal = Signal.create(type, data); Signal signal = Signal.create(type, data);
@ -124,7 +124,7 @@ public class SignalSystem implements Service {
} else { } else {
//there are no services mapped to this signal type //there are no services mapped to this signal type
} }
systemLock.release(); systemLock.unlock();
} }
/** /**

View File

@ -1,7 +1,6 @@
package electrosphere.net.client; package electrosphere.net.client;
import java.util.List; import java.util.LinkedList;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
@ -41,7 +40,7 @@ public class MessageProtocol {
Semaphore synchronousMessageLock = new Semaphore(1); Semaphore synchronousMessageLock = new Semaphore(1);
//the queue of synchonous network messages //the queue of synchonous network messages
List<NetworkMessage> synchronousMessageQueue = new CopyOnWriteArrayList<NetworkMessage>(); LinkedList<NetworkMessage> synchronousMessageQueue = new LinkedList<NetworkMessage>();
//The individual protocols //The individual protocols

View File

@ -1,13 +1,14 @@
package electrosphere.net.parser.net.raw; package electrosphere.net.parser.net.raw;
import electrosphere.net.parser.net.message.MessagePool; import electrosphere.net.parser.net.message.MessagePool;
import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.parser.net.message.NetworkMessage;
import io.github.studiorailgun.CircularByteBuffer; import io.github.studiorailgun.CircularByteBuffer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.locks.ReentrantLock;
/** /**
* The main message parser. This is used to serialize/deserialize messages to/from the provided streams. * The main message parser. This is used to serialize/deserialize messages to/from the provided streams.
@ -37,12 +38,12 @@ public class NetworkParser {
/** /**
* The queue of incoming messages that have been parsed * The queue of incoming messages that have been parsed
*/ */
CopyOnWriteArrayList<NetworkMessage> incomingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>(); LinkedList<NetworkMessage> incomingMessageQueue = new LinkedList<NetworkMessage>();
/** /**
* The queue of outgoing messages that have yet to be sent * The queue of outgoing messages that have yet to be sent
*/ */
CopyOnWriteArrayList<NetworkMessage> outgoingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>(); LinkedList<NetworkMessage> outgoingMessageQueue = new LinkedList<NetworkMessage>();
/** /**
* Message object pool * Message object pool
@ -59,11 +60,6 @@ public class NetworkParser {
*/ */
byte[] readBuffer = new byte[READ_BLOCK_SIZE]; byte[] readBuffer = new byte[READ_BLOCK_SIZE];
/**
* The outgoing byte buffer
*/
CopyOnWriteArrayList<Byte> outgoingByteQueue = new CopyOnWriteArrayList<Byte>();
/** /**
* The number of bytes read * The number of bytes read
*/ */
@ -74,6 +70,11 @@ public class NetworkParser {
* Otherwise, will not release when the message is sent. * Otherwise, will not release when the message is sent.
*/ */
boolean releaseOnSend = true; boolean releaseOnSend = true;
/**
* Lock for thread-safing the parser
*/
ReentrantLock lock = new ReentrantLock();
/** /**
@ -103,9 +104,11 @@ public class NetworkParser {
//parse byte queue for messages //parse byte queue for messages
//for each message, append to clientIncomingMessageQueue //for each message, append to clientIncomingMessageQueue
NetworkMessage newMessage; NetworkMessage newMessage;
lock.lock();
while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer,this.pool))!=null){ while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer,this.pool))!=null){
incomingMessageQueue.add(newMessage); incomingMessageQueue.add(newMessage);
} }
lock.unlock();
} }
/** /**
@ -113,13 +116,15 @@ public class NetworkParser {
* @throws IOException Thrown if a message fails to serialize or the output stream fails to write * @throws IOException Thrown if a message fails to serialize or the output stream fails to write
*/ */
public void pushMessagesOut() throws IOException { public void pushMessagesOut() throws IOException {
lock.lock();
for(NetworkMessage message : outgoingMessageQueue){ for(NetworkMessage message : outgoingMessageQueue){
outgoingMessageQueue.remove(message);
outgoingStream.write(message.getRawBytes()); outgoingStream.write(message.getRawBytes());
if(this.releaseOnSend){ if(this.releaseOnSend){
this.pool.release(message); this.pool.release(message);
} }
} }
outgoingMessageQueue.clear();
lock.unlock();
} }
/** /**
@ -127,7 +132,10 @@ public class NetworkParser {
* @return true if there is message in the queue, false otherwise * @return true if there is message in the queue, false otherwise
*/ */
public boolean hasIncomingMessaage(){ public boolean hasIncomingMessaage(){
return incomingMessageQueue.size() > 0; lock.lock();
boolean rVal = incomingMessageQueue.size() > 0;
lock.unlock();
return rVal;
} }
/** /**
@ -135,7 +143,10 @@ public class NetworkParser {
* @return The message * @return The message
*/ */
public NetworkMessage popIncomingMessage(){ public NetworkMessage popIncomingMessage(){
return incomingMessageQueue.remove(0); lock.lock();
NetworkMessage rVal = incomingMessageQueue.remove(0);
lock.unlock();
return rVal;
} }
/** /**
@ -143,7 +154,9 @@ public class NetworkParser {
* @param message The message * @param message The message
*/ */
public void addOutgoingMessage(NetworkMessage message){ public void addOutgoingMessage(NetworkMessage message){
lock.lock();
outgoingMessageQueue.add(message); outgoingMessageQueue.add(message);
lock.unlock();
} }
/** /**
@ -151,7 +164,9 @@ public class NetworkParser {
* @param messages The list to copy the incoming messages to * @param messages The list to copy the incoming messages to
*/ */
public void copyIncomingMessages(List<NetworkMessage> messages){ public void copyIncomingMessages(List<NetworkMessage> messages){
lock.lock();
messages.addAll(incomingMessageQueue); messages.addAll(incomingMessageQueue);
lock.unlock();
} }
/** /**
@ -159,7 +174,9 @@ public class NetworkParser {
* @param messages The list to copy the outgoing messages to * @param messages The list to copy the outgoing messages to
*/ */
public void copyOutgoingMessages(List<NetworkMessage> messages){ public void copyOutgoingMessages(List<NetworkMessage> messages){
lock.lock();
messages.addAll(outgoingMessageQueue); messages.addAll(outgoingMessageQueue);
lock.unlock();
} }
/** /**

View File

@ -1,7 +1,6 @@
package electrosphere.net.server; package electrosphere.net.server;
import java.util.List; import java.util.LinkedList;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
@ -37,7 +36,7 @@ public class MessageProtocol {
Semaphore synchronousMessageLock = new Semaphore(1); Semaphore synchronousMessageLock = new Semaphore(1);
//the queue of synchonous network messages //the queue of synchonous network messages
List<NetworkMessage> synchronousMessageQueue = new CopyOnWriteArrayList<NetworkMessage>(); LinkedList<NetworkMessage> synchronousMessageQueue = new LinkedList<NetworkMessage>();
//The server connection handler //The server connection handler
ServerConnectionHandler serverConnectionHandler; ServerConnectionHandler serverConnectionHandler;

View File

@ -16,7 +16,6 @@ import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -127,11 +126,6 @@ public class ServerConnectionHandler implements Runnable {
* the lock used for synchronizing the synchronous message queue * the lock used for synchronizing the synchronous message queue
*/ */
Semaphore synchronousMessageLock = new Semaphore(1); Semaphore synchronousMessageLock = new Semaphore(1);
/**
* the queue of synchonous network messages
*/
List<NetworkMessage> synchronousMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
/** /**
* Constructs a connection from a socket * Constructs a connection from a socket

View File

@ -1,13 +1,13 @@
package electrosphere.renderer.ui; package electrosphere.renderer.ui;
import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.Stack; import java.util.Stack;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Vector2i; import org.joml.Vector2i;
@ -51,13 +51,18 @@ public class ElementService extends SignalServiceImpl {
); );
} }
Map<String,Element> elementMap = new ConcurrentHashMap<String,Element>(); Map<String,Element> elementMap = new HashMap<String,Element>();
List<Element> elementList = new CopyOnWriteArrayList<Element>(); List<Element> elementList = new LinkedList<Element>();
FocusableElement currentFocusedElement = null; FocusableElement currentFocusedElement = null;
DraggableElement currentDragElement = null; DraggableElement currentDragElement = null;
// the element currently hovered over // the element currently hovered over
HoverableElement currentHoveredElement = null; HoverableElement currentHoveredElement = null;
/**
* Lock for thread-safing the structure
*/
ReentrantLock lock = new ReentrantLock();
/** /**
* Registers a window * Registers a window
@ -65,6 +70,7 @@ public class ElementService extends SignalServiceImpl {
* @param w The window element * @param w The window element
*/ */
public void registerWindow(String name, Element w){ public void registerWindow(String name, Element w){
lock.lock();
elementMap.put(name,w); elementMap.put(name,w);
if(!elementList.contains(w)){ if(!elementList.contains(w)){
elementList.add(w); elementList.add(w);
@ -72,6 +78,7 @@ public class ElementService extends SignalServiceImpl {
if(elementList.size() < 2){ if(elementList.size() < 2){
focusFirstElement(); focusFirstElement();
} }
lock.unlock();
} }
/** /**
@ -80,7 +87,11 @@ public class ElementService extends SignalServiceImpl {
* @return The window element if it exists, null otherwise * @return The window element if it exists, null otherwise
*/ */
public Element getWindow(String name){ public Element getWindow(String name){
return elementMap.get(name); Element rVal = null;
lock.lock();
rVal = elementMap.get(name);
lock.unlock();
return rVal;
} }
/** /**
@ -88,7 +99,10 @@ public class ElementService extends SignalServiceImpl {
* @return The list of all registered windows * @return The list of all registered windows
*/ */
public List<Element> getWindowList(){ public List<Element> getWindowList(){
return elementList; lock.lock();
List<Element> rVal = new LinkedList<Element>(this.elementList);
lock.unlock();
return rVal;
} }
/** /**
@ -96,6 +110,7 @@ public class ElementService extends SignalServiceImpl {
* @param name The window string * @param name The window string
*/ */
public void unregisterWindow(String name){ public void unregisterWindow(String name){
lock.lock();
Element w = elementMap.remove(name); Element w = elementMap.remove(name);
while(elementList.contains(w)){ while(elementList.contains(w)){
elementList.remove(w); elementList.remove(w);
@ -105,15 +120,21 @@ public class ElementService extends SignalServiceImpl {
} else { } else {
this.currentFocusedElement = null; this.currentFocusedElement = null;
} }
lock.unlock();
} }
public boolean containsWindow(String name){ public boolean containsWindow(String name){
return elementMap.containsKey(name); lock.lock();
boolean rVal = elementMap.containsKey(name);
lock.unlock();
return rVal;
} }
public void pushWindowToFront(Window window){ public void pushWindowToFront(Window window){
lock.lock();
elementList.remove(window); elementList.remove(window);
elementList.add(window); elementList.add(window);
lock.unlock();
} }
/** /**
@ -121,7 +142,10 @@ public class ElementService extends SignalServiceImpl {
* @return The set of ids * @return The set of ids
*/ */
public Set<String> getCurrentWindowIds(){ public Set<String> getCurrentWindowIds(){
return elementMap.keySet(); lock.lock();
Set<String> rVal = elementMap.keySet();
lock.unlock();
return rVal;
} }
/** /**
@ -159,6 +183,7 @@ public class ElementService extends SignalServiceImpl {
} }
public void focusFirstElement(){ public void focusFirstElement(){
lock.lock();
if(elementList.size() > 0){ if(elementList.size() > 0){
List<FocusableElement> focusables = getFocusableList(elementList.get(elementList.size() - 1),new LinkedList<FocusableElement>()); List<FocusableElement> focusables = getFocusableList(elementList.get(elementList.size() - 1),new LinkedList<FocusableElement>());
if(focusables.size() > 0){ if(focusables.size() > 0){
@ -174,10 +199,13 @@ public class ElementService extends SignalServiceImpl {
currentFocusedElement = null; currentFocusedElement = null;
} }
} }
lock.unlock();
} }
public void focusNextElement(){ public void focusNextElement(){
lock.lock();
List<FocusableElement> focusables = getFocusableList(elementList.get(elementList.size() - 1),new LinkedList<FocusableElement>()); List<FocusableElement> focusables = getFocusableList(elementList.get(elementList.size() - 1),new LinkedList<FocusableElement>());
lock.unlock();
if(focusables.contains(currentFocusedElement)){ if(focusables.contains(currentFocusedElement)){
int index = focusables.indexOf(currentFocusedElement); int index = focusables.indexOf(currentFocusedElement);
if(index + 1 >= focusables.size()){ if(index + 1 >= focusables.size()){
@ -194,7 +222,9 @@ public class ElementService extends SignalServiceImpl {
} }
public void focusPreviousElement(){ public void focusPreviousElement(){
lock.lock();
List<FocusableElement> focusables = getFocusableList(elementList.get(elementList.size() - 1),new LinkedList<FocusableElement>()); List<FocusableElement> focusables = getFocusableList(elementList.get(elementList.size() - 1),new LinkedList<FocusableElement>());
lock.unlock();
if(focusables.contains(currentFocusedElement)){ if(focusables.contains(currentFocusedElement)){
int index = focusables.indexOf(currentFocusedElement); int index = focusables.indexOf(currentFocusedElement);
if(index - 1 < 0){ if(index - 1 < 0){
@ -230,7 +260,9 @@ public class ElementService extends SignalServiceImpl {
*/ */
public void fireEvent(Event event, int x, int y){ public void fireEvent(Event event, int x, int y){
boolean propagate = true; boolean propagate = true;
lock.lock();
ListIterator<Element> windowIterator = elementList.listIterator(elementList.size()); ListIterator<Element> windowIterator = elementList.listIterator(elementList.size());
lock.unlock();
while(windowIterator.hasPrevious()){ while(windowIterator.hasPrevious()){
Element currentWindow = windowIterator.previous(); Element currentWindow = windowIterator.previous();
Stack<Element> elementStack = buildElementPositionalStack(new Stack<Element>(), currentWindow, x, y); Stack<Element> elementStack = buildElementPositionalStack(new Stack<Element>(), currentWindow, x, y);
@ -283,12 +315,14 @@ public class ElementService extends SignalServiceImpl {
*/ */
public void fireTopLevelEvent(Event event){ public void fireTopLevelEvent(Event event){
boolean propagate = true; boolean propagate = true;
lock.lock();
for(Element topLevelEl : this.elementList){ for(Element topLevelEl : this.elementList){
propagate = fireEventNoPosition(event, topLevelEl); propagate = fireEventNoPosition(event, topLevelEl);
if(!propagate){ if(!propagate){
break; break;
} }
} }
lock.unlock();
} }
/** /**
@ -358,6 +392,7 @@ public class ElementService extends SignalServiceImpl {
} }
public Element resolveFirstDraggable(DragEvent event){ public Element resolveFirstDraggable(DragEvent event){
lock.lock();
ListIterator<Element> windowIterator = elementList.listIterator(elementList.size()); ListIterator<Element> windowIterator = elementList.listIterator(elementList.size());
while(windowIterator.hasPrevious()){ while(windowIterator.hasPrevious()){
Element currentWindow = windowIterator.previous(); Element currentWindow = windowIterator.previous();
@ -366,10 +401,12 @@ public class ElementService extends SignalServiceImpl {
while(elementStack.size() > 0){ while(elementStack.size() > 0){
currentElement = elementStack.pop(); currentElement = elementStack.pop();
if(currentElement instanceof DraggableElement){ if(currentElement instanceof DraggableElement){
lock.unlock();
return currentElement; return currentElement;
} }
} }
} }
lock.unlock();
return null; return null;
} }
@ -380,6 +417,7 @@ public class ElementService extends SignalServiceImpl {
* @return The first hoverable element if it exists, null otherwise * @return The first hoverable element if it exists, null otherwise
*/ */
public Element resolveFirstHoverable(int currentX, int currentY){ public Element resolveFirstHoverable(int currentX, int currentY){
lock.lock();
ListIterator<Element> windowIterator = elementList.listIterator(elementList.size()); ListIterator<Element> windowIterator = elementList.listIterator(elementList.size());
while(windowIterator.hasPrevious()){ while(windowIterator.hasPrevious()){
Element currentWindow = windowIterator.previous(); Element currentWindow = windowIterator.previous();
@ -388,10 +426,12 @@ public class ElementService extends SignalServiceImpl {
while(elementStack.size() > 0){ while(elementStack.size() > 0){
currentElement = elementStack.pop(); currentElement = elementStack.pop();
if(currentElement instanceof HoverableElement){ if(currentElement instanceof HoverableElement){
lock.unlock();
return currentElement; return currentElement;
} }
} }
} }
lock.unlock();
return null; return null;
} }
@ -497,10 +537,13 @@ public class ElementService extends SignalServiceImpl {
*/ */
public void navigateBackwards(){ public void navigateBackwards(){
NavigationEvent event = new NavigationEvent(NavigationEventType.BACKWARD); NavigationEvent event = new NavigationEvent(NavigationEventType.BACKWARD);
lock.lock();
int elListSize = this.elementList.size();
lock.unlock();
if(currentFocusedElement != null){ if(currentFocusedElement != null){
//fires on the currently focused element //fires on the currently focused element
fireEventNoPosition(event, currentFocusedElement); fireEventNoPosition(event, currentFocusedElement);
} else if(this.elementList.size() > 0){ } else if(elListSize > 0){
fireTopLevelEvent(event); fireTopLevelEvent(event);
} }
} }

View File

@ -1,8 +1,5 @@
package electrosphere.server.physics.terrain.generation; package electrosphere.server.physics.terrain.generation;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import electrosphere.client.terrain.cache.ChunkData; import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator; import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
@ -19,7 +16,7 @@ public class OverworldChunkGenerator implements ChunkGenerator {
//cache for the bicubic interpolated chunks //cache for the bicubic interpolated chunks
//don't need to interpolate each time a new chunk is created //don't need to interpolate each time a new chunk is created
//This should eventually be removed as terrain generation becomes more complicated than a heightmap //This should eventually be removed as terrain generation becomes more complicated than a heightmap
Map<String, float[][]> heightmapCache = new ConcurrentHashMap<String, float[][]>(); // Map<String, float[][]> heightmapCache = new ConcurrentHashMap<String, float[][]>();
/** /**
* Constructor * Constructor