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)
Fix voxel pathfinding logic
Remove several usages of concurrent datastructures

View File

@ -1,7 +1,8 @@
package electrosphere.client.scene;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import org.joml.Vector3d;
import org.ode4j.ode.DContactGeom;
@ -24,11 +25,11 @@ import electrosphere.logger.LoggerInterface;
public class ClientSceneWrapper {
//entity id translation between server/client
Map<Integer,Integer> clientToServerIdMap = new ConcurrentHashMap<Integer,Integer>();
Map<Integer,Integer> serverToClientIdMap = new ConcurrentHashMap<Integer,Integer>();
Map<Integer,Integer> clientToServerIdMap = new HashMap<Integer,Integer>();
Map<Integer,Integer> serverToClientIdMap = new HashMap<Integer,Integer>();
//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
Scene scene;
@ -49,6 +50,11 @@ public class ClientSceneWrapper {
//The hitbox manager
HitboxManager hitboxManager;
/**
* Lock for threadsafing the scene wrapper
*/
ReentrantLock lock = new ReentrantLock();
/**
* Constructor
* @param scene The scene
@ -71,8 +77,10 @@ public class ClientSceneWrapper {
*/
public void mapIdToId(int clientId, int serverId){
LoggerInterface.loggerNetworking.DEBUG("[CLIENT] MapID: " + clientId + " <===> " + serverId);
lock.lock();
clientToServerIdMap.put(clientId, serverId);
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
*/
public int mapClientToServerId(int clientId){
lock.lock();
if(clientToServerIdMap.get(clientId) == null){
LoggerInterface.loggerNetworking.ERROR(new Error("Failed to map client entity " + clientId + " to server entity!"));
lock.unlock();
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
*/
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
*/
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
*/
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
*/
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
*/
public void deregisterTranslationMapping(Entity clientEntity){
lock.lock();
if(this.clientToServerMapContainsId(clientEntity.getId())){
//remove from client->server map
int serverId = clientToServerIdMap.remove(clientEntity.getId());
@ -138,6 +163,7 @@ public class ClientSceneWrapper {
deletedServerIds.put(serverId,true);
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
*/
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
*/
public Entity getEntityFromServerId(int id){
Entity rVal = null;
lock.lock();
if(serverToClientIdMap.containsKey(id)){
int clientId = mapServerToClientId(id);
return scene.getEntityFromId(clientId);
} else {
return null;
rVal = scene.getEntityFromId(clientId);
}
lock.unlock();
return rVal;
}
/**
* Dumps the status of the network translation layer
*/
public void dumpTranslationLayerStatus(){
lock.lock();
LoggerInterface.loggerNetworking.WARNING("Client -> Server keys");
LoggerInterface.loggerNetworking.WARNING(clientToServerIdMap.keySet() + "");
LoggerInterface.loggerNetworking.WARNING("Server -> Client keys");
LoggerInterface.loggerNetworking.WARNING(serverToClientIdMap.keySet() + "");
lock.unlock();
}
/**
@ -179,6 +212,7 @@ public class ClientSceneWrapper {
* @param id The id
*/
public void dumpIdData(int id){
lock.lock();
LoggerInterface.loggerNetworking.WARNING("Offending ID " + id);
LoggerInterface.loggerNetworking.WARNING("Client->Server Map contains? " + clientToServerIdMap.containsKey(id));
LoggerInterface.loggerNetworking.WARNING("Server->Client Map contains? " + serverToClientIdMap.containsKey(id));
@ -188,6 +222,7 @@ public class ClientSceneWrapper {
if(serverToClientIdMap.containsKey(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.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantLock;
import org.lwjgl.assimp.AIScene;
@ -40,43 +39,47 @@ import org.ode4j.ode.DBody;
*/
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>();
/**
* Lock for thread-safing the work
*/
ReentrantLock lock = new ReentrantLock();
Map<String,Texture> texturesLoadedIntoMemory = new ConcurrentHashMap<String,Texture>();
List<String> texturesInQueue = new CopyOnWriteArrayList<String>();
List<String> texturesInDeleteQueue = new CopyOnWriteArrayList<String>();
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,AudioBuffer> audioLoadedIntoMemory = new ConcurrentHashMap<String,AudioBuffer>();
List<String> audioInQueue = new CopyOnWriteArrayList<String>();
Map<String,Texture> texturesLoadedIntoMemory = new HashMap<String,Texture>();
List<String> texturesInQueue = new LinkedList<String>();
List<String> texturesInDeleteQueue = new LinkedList<String>();
Map<String,VisualShader> shadersLoadedIntoMemory = new ConcurrentHashMap<String,VisualShader>();
List<ActorShaderMask> shadersInQueue = new CopyOnWriteArrayList<ActorShaderMask>();
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
//
Map<String,ComputeShader> computeShadersLoadedIntoMemory = new ConcurrentHashMap<String,ComputeShader>();
List<String> computeShadersInQueue = new CopyOnWriteArrayList<String>();
Map<String,ComputeShader> computeShadersLoadedIntoMemory = new HashMap<String,ComputeShader>();
List<String> computeShadersInQueue = new LinkedList<String>();
Map<String,DBody> physicsMeshesLoadedIntoMemory = new ConcurrentHashMap<String,DBody>();
List<PhysicsMeshQueueItem> physicsMeshesToLoad = new CopyOnWriteArrayList<PhysicsMeshQueueItem>();
Map<String,DBody> physicsMeshesLoadedIntoMemory = new HashMap<String,DBody>();
List<PhysicsMeshQueueItem> physicsMeshesToLoad = new LinkedList<PhysicsMeshQueueItem>();
Map<String,PoseModel> poseModelsLoadedIntoMemory = new ConcurrentHashMap<String,PoseModel>();
List<String> poseModelsInQueue = new CopyOnWriteArrayList<String>();
List<String> poseModelsInDeleteQueue = new CopyOnWriteArrayList<String>();
Map<String,PoseModel> poseModelsLoadedIntoMemory = new HashMap<String,PoseModel>();
List<String> poseModelsInQueue = new LinkedList<String>();
List<String> poseModelsInDeleteQueue = new LinkedList<String>();
//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
List<HomogenousInstancedArray> instanceArrayBufferAllocationQueue = new CopyOnWriteArrayList<HomogenousInstancedArray>();
List<HomogenousInstancedArray> instanceArrayBufferAllocationQueue = new LinkedList<HomogenousInstancedArray>();
//assets queued to be loaded
ReentrantLock queuedAssetLock = new ReentrantLock();
List<QueuedAsset<?>> queuedAssets = new LinkedList<QueuedAsset<?>>();
/**
@ -98,8 +101,8 @@ public class AssetManager {
//models
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load models");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load Models");
lock.lock();
for(String currentPath : modelsInQueue){
modelsInQueue.remove(currentPath);
AIScene aiScene = ModelLoader.loadAIScene(currentPath);
TextureMap textureMap = null;
if(this.getLocalTextureMapPath(currentPath) != null){
@ -119,43 +122,43 @@ public class AssetManager {
}
}
}
modelsInQueue.clear();
Globals.profiler.endCpuSample();
//textures from disk to gpu
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load textures");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load textures");
for(String currentPath : texturesInQueue){
texturesInQueue.remove(currentPath);
Texture tex = new Texture(Globals.renderingEngine.getOpenGLState(), currentPath);
texturesLoadedIntoMemory.put(currentPath, tex);
}
texturesInQueue.clear();
Globals.profiler.endCpuSample();
//audio from disk
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load audio");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load audio");
if(Globals.audioEngine != null && Globals.audioEngine.initialized()){
for(String currentPath : audioInQueue){
audioInQueue.remove(currentPath);
audioLoadedIntoMemory.put(currentPath, new AudioBuffer(currentPath));
}
audioInQueue.clear();
}
Globals.profiler.endCpuSample();
//shaders
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load visual shaders");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load visual shaders");
for(ActorShaderMask currentShader : shadersInQueue){
shadersInQueue.remove(currentShader);
String key = getShaderKey(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath());
shadersLoadedIntoMemory.put(
key,
VisualShader.loadSpecificShader(currentShader.getVertexShaderPath(),currentShader.getFragmentShaderPath())
);
}
shadersInQueue.clear();
Globals.profiler.endCpuSample();
//compute shaders
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load compute shaders");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load compute shaders");
for(String computePath : computeShadersInQueue){
computeShadersInQueue.remove(computePath);
String key = getComputeShaderKey(computePath);
try {
computeShadersLoadedIntoMemory.put(
@ -166,20 +169,20 @@ public class AssetManager {
e.printStackTrace();
}
}
computeShadersInQueue.clear();
Globals.profiler.endCpuSample();
//pose models
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load pose models");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load pose models");
for(String currentPath: poseModelsInQueue){
poseModelsInQueue.remove(currentPath);
AIScene scene = ModelLoader.loadAIScene(currentPath);
poseModelsLoadedIntoMemory.put(currentPath, new PoseModel(currentPath, scene));
}
poseModelsInQueue.clear();
Globals.profiler.endCpuSample();
//queued assets
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Load queued assets");
Globals.profiler.beginCpuSample("AssetManager.loadAssetsInQueue - Load queued assets");
queuedAssetLock.lock();
if(queuedAssets.size() > MAX_ASSETS_PER_FRAME){
for(int i = 0; i < MAX_ASSETS_PER_FRAME; i++){
QueuedAsset<?> queuedAsset = queuedAssets.remove(0);
@ -201,7 +204,6 @@ public class AssetManager {
}
queuedAssets.clear();
}
queuedAssetLock.unlock();
Globals.profiler.endCpuSample();
//allocate homogenous buffers
@ -219,6 +221,8 @@ public class AssetManager {
//override meshes
LoggerInterface.loggerEngine.DEBUG_LOOP("AssetManager - Override meshes");
this.performMeshOverrides();
lock.unlock();
}
@ -228,6 +232,7 @@ public class AssetManager {
public void updateAsset(String path){
LoggerInterface.loggerEngine.DEBUG("AssetManager - updateAsset");
//models
lock.lock();
if(modelsLoadedIntoMemory.containsKey(path)){
this.queueModelForDeletion(path);
this.deleteModelsInDeleteQueue();
@ -254,15 +259,18 @@ public class AssetManager {
if(computeShadersLoadedIntoMemory.containsKey(path)){
throw new Error("Unhandled asset type! (Shader - Compute)");
}
lock.unlock();
}
/**
* Handles the delete queues
*/
public void handleDeleteQueue(){
lock.lock();
this.deleteModelsInDeleteQueue();
this.deletePoseModelsInDeleteQueue();
this.deleteTexturesInDeleteQueue();
lock.unlock();
}
@ -277,16 +285,20 @@ public class AssetManager {
//
public void addModelPathToQueue(String path){
lock.lock();
if(!modelsInQueue.contains(path) && !modelsLoadedIntoMemory.containsKey(path)){
modelsInQueue.add(path);
}
lock.unlock();
}
public Model fetchModel(String path){
Model rVal = null;
lock.lock();
if(modelsLoadedIntoMemory.containsKey(path)){
rVal = modelsLoadedIntoMemory.get(path);
}
lock.unlock();
return rVal;
}
@ -295,7 +307,9 @@ public class AssetManager {
* @param modelPath The path to the model
*/
public void queueModelForDeletion(String modelPath){
lock.lock();
modelsInDeleteQueue.add(modelPath);
lock.unlock();
}
/**
@ -306,7 +320,9 @@ public class AssetManager {
String rVal;
UUID newUUID = UUID.randomUUID();
rVal = newUUID.toString();
lock.lock();
modelsLoadedIntoMemory.put(rVal,m);
lock.unlock();
return rVal;
}
@ -317,20 +333,27 @@ public class AssetManager {
* @param path The path to register the model to
*/
public void registerModelWithPath(Model m, String path){
lock.lock();
modelsLoadedIntoMemory.put(path, m);
lock.unlock();
}
public void deregisterModelPath(String path){
lock.lock();
modelsLoadedIntoMemory.remove(path);
lock.unlock();
}
public void queueOverrideMeshShader(String modelName, String meshName, String vertPath, String fragPath){
lock.lock();
MeshShaderOverride override = new MeshShaderOverride(modelName,meshName,vertPath,fragPath);
shaderOverrides.add(override);
lock.unlock();
}
public void performMeshOverrides(){
List<MeshShaderOverride> toRemove = new LinkedList<MeshShaderOverride>();
lock.lock();
for(MeshShaderOverride shaderOverride : shaderOverrides){
Model model = null;
if((model = fetchModel(shaderOverride.modelName)) != null){
@ -345,25 +368,28 @@ public class AssetManager {
for(MeshShaderOverride shaderOverride : toRemove){
shaderOverrides.remove(shaderOverride);
}
lock.unlock();
}
/**
* Nuclear function, reloads all shaders loaded into memory
*/
public void forceReloadAllModels(){
lock.lock();
for(String modelKey : modelsLoadedIntoMemory.keySet()){
if(modelKey.contains("Models")){
modelsInQueue.add(modelKey);
modelsLoadedIntoMemory.remove(modelKey);
}
}
// modelsLoadedIntoMemory.clear();
lock.unlock();
}
/**
* Deletes all models in the delete queue
*/
public void deleteModelsInDeleteQueue(){
lock.lock();
for(String modelPath : modelsInDeleteQueue){
Model model = this.fetchModel(modelPath);
if(model != null){
@ -371,6 +397,7 @@ public class AssetManager {
}
this.modelsLoadedIntoMemory.remove(modelPath);
}
lock.unlock();
}
@ -388,9 +415,11 @@ public class AssetManager {
* @param path The path to load
*/
public void addPoseModelPathToQueue(String path){
lock.lock();
if(!poseModelsInQueue.contains(path) && !poseModelsLoadedIntoMemory.containsKey(path)){
poseModelsInQueue.add(path);
}
lock.unlock();
}
/**
@ -400,9 +429,11 @@ public class AssetManager {
*/
public PoseModel fetchPoseModel(String path){
PoseModel rVal = null;
lock.lock();
if(poseModelsLoadedIntoMemory.containsKey(path)){
rVal = poseModelsLoadedIntoMemory.get(path);
}
lock.unlock();
return rVal;
}
@ -413,7 +444,9 @@ public class AssetManager {
* @param path The path to register the pose model to
*/
public void registerPoseModelWithPath(PoseModel m, String path){
lock.lock();
poseModelsLoadedIntoMemory.put(path, m);
lock.unlock();
}
/**
@ -421,13 +454,16 @@ public class AssetManager {
* @param modelPath The path to the pose model
*/
public void queuePoseModelForDeletion(String modelPath){
lock.lock();
poseModelsInDeleteQueue.add(modelPath);
lock.unlock();
}
/**
* Deletes all pose models in the delete queue
*/
public void deletePoseModelsInDeleteQueue(){
lock.lock();
for(String modelPath : poseModelsInDeleteQueue){
PoseModel poseModel = this.fetchPoseModel(modelPath);
if(poseModel != null){
@ -435,6 +471,7 @@ public class AssetManager {
}
this.poseModelsLoadedIntoMemory.remove(modelPath);
}
lock.unlock();
}
@ -451,9 +488,11 @@ public class AssetManager {
public void addTexturePathtoQueue(String path){
lock.lock();
if(!texturesInQueue.contains(path) && !texturesLoadedIntoMemory.containsKey(path)){
texturesInQueue.add(path);
}
lock.unlock();
}
/**
@ -461,14 +500,18 @@ public class AssetManager {
* @param texturePath The path to the texture
*/
public void queueTextureForDeletion(String texturePath){
lock.lock();
texturesInDeleteQueue.add(texturePath);
lock.unlock();
}
public Texture fetchTexture(String path){
Texture rVal = null;
lock.lock();
if(texturesLoadedIntoMemory.containsKey(path)){
rVal = texturesLoadedIntoMemory.get(path);
}
lock.unlock();
return rVal;
}
@ -476,7 +519,9 @@ public class AssetManager {
String rVal;
UUID newUUID = UUID.randomUUID();
rVal = newUUID.toString();
lock.lock();
texturesLoadedIntoMemory.put(rVal,t);
lock.unlock();
return rVal;
}
@ -486,11 +531,16 @@ public class AssetManager {
* @param path The path
*/
public void registerTextureToPath(Texture t, String path){
lock.lock();
texturesLoadedIntoMemory.put(path,t);
lock.unlock();
}
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
*/
private String getLocalTextureMapPath(String modelPath){
lock.lock();
File modelFile = FileUtils.getAssetFile(modelPath);
File containingDirectory = modelFile.getParentFile();
File[] children = containingDirectory.listFiles();
@ -506,10 +557,12 @@ public class AssetManager {
if(child.getName().equals("texturemap.json")){
String rVal = child.getPath();
String fixed = rVal.replace(".\\assets", "").replace("./assets", "");
lock.unlock();
return fixed;
}
}
}
lock.unlock();
return null;
}
@ -517,6 +570,7 @@ public class AssetManager {
* Deletes all textures in the delete queue
*/
public void deleteTexturesInDeleteQueue(){
lock.lock();
for(String texturePath : texturesInDeleteQueue){
Texture texture = this.fetchTexture(texturePath);
if(texture != null){
@ -524,6 +578,7 @@ public class AssetManager {
}
this.texturesLoadedIntoMemory.remove(texturePath);
}
lock.unlock();
}
@ -539,13 +594,16 @@ public class AssetManager {
//
public void addAudioPathToQueue(String path){
lock.lock();
String sanitizedPath = FileUtils.sanitizeFilePath(path);
if(!audioInQueue.contains(sanitizedPath) && !audioLoadedIntoMemory.containsKey(sanitizedPath)){
audioInQueue.add(sanitizedPath);
}
lock.unlock();
}
public AudioBuffer fetchAudio(String path){
lock.lock();
AudioBuffer rVal = null;
String sanitizedPath = FileUtils.sanitizeFilePath(path);
if(audioLoadedIntoMemory.containsKey(sanitizedPath)){
@ -553,6 +611,7 @@ public class AssetManager {
} else {
LoggerInterface.loggerAudio.WARNING("Failed to find audio " + sanitizedPath);
}
lock.unlock();
return rVal;
}
@ -561,7 +620,10 @@ public class AssetManager {
* @return The collection of all audio buffers
*/
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
//
public void addShaderToQueue(String vertexShader, String fragmentShader){
lock.lock();
shadersInQueue.add(new ActorShaderMask("","",vertexShader,fragmentShader));
lock.unlock();
}
public VisualShader fetchShader(String vertexPath, String fragmentPath){
lock.lock();
String path = getShaderKey(vertexPath,fragmentPath);
VisualShader rVal = null;
if(shadersLoadedIntoMemory.containsKey(path)){
rVal = shadersLoadedIntoMemory.get(path);
}
lock.unlock();
return rVal;
}
@ -595,11 +661,13 @@ public class AssetManager {
* Nuclear function, reloads all shaders loaded into memory
*/
public void forceReloadAllShaders(){
lock.lock();
for(String shaderKey : shadersLoadedIntoMemory.keySet()){
String shaderPaths[] = shaderKey.split("-");
shadersInQueue.add(new ActorShaderMask("","",shaderPaths[0],shaderPaths[1]));
}
shadersLoadedIntoMemory.clear();
lock.unlock();
}
//
@ -610,7 +678,9 @@ public class AssetManager {
* @param computePath The path to the source code for the shader
*/
public void addComputeShaderToQueue(String computePath){
lock.lock();
computeShadersInQueue.add(getComputeShaderKey(computePath));
lock.unlock();
}
/**
@ -619,11 +689,13 @@ public class AssetManager {
* @return The compute shader if it exists, null otherwise
*/
public ComputeShader fetchComputeShader(String computePath){
lock.lock();
String key = getComputeShaderKey(computePath);
ComputeShader rVal = null;
if(computeShadersLoadedIntoMemory.containsKey(key)){
rVal = computeShadersLoadedIntoMemory.get(key);
}
lock.unlock();
return rVal;
}
@ -643,6 +715,7 @@ public class AssetManager {
//COLLISION MESH
//
public void addCollisionMeshToQueue(PhysicsMeshQueueItem physicsMeshQueueItem){
lock.lock();
if(
!physicsMeshesToLoad.contains(physicsMeshQueueItem) &&
!physicsMeshesLoadedIntoMemory.containsKey(getCollisionMeshMapKey(
@ -651,10 +724,14 @@ public class AssetManager {
))){
physicsMeshesToLoad.add(physicsMeshQueueItem);
}
lock.unlock();
}
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
*/
public void allocateHomogenousBuffers(){
lock.lock();
for(HomogenousUniformBuffer buffer : homogenousBufferAllocationQueue){
buffer.allocate();
}
homogenousBufferAllocationQueue.clear();
lock.unlock();
}
/**
@ -686,7 +765,9 @@ public class AssetManager {
* @param buffer The buffer
*/
public void addHomogenousBufferToQueue(HomogenousUniformBuffer buffer){
lock.lock();
homogenousBufferAllocationQueue.add(buffer);
lock.unlock();
}
@ -697,10 +778,12 @@ public class AssetManager {
* Allocates all instance array buffers in queue
*/
public void allocateInstanceArrayBuffers(){
lock.lock();
for(HomogenousInstancedArray buffer : instanceArrayBufferAllocationQueue){
buffer.allocate();
}
instanceArrayBufferAllocationQueue.clear();
lock.unlock();
}
/**
@ -708,7 +791,9 @@ public class AssetManager {
* @param buffer The buffer
*/
public void addInstanceArrayBufferToQueue(HomogenousInstancedArray buffer){
lock.lock();
instanceArrayBufferAllocationQueue.add(buffer);
lock.unlock();
}
@ -720,7 +805,7 @@ public class AssetManager {
* @param asset the asset
*/
public String queuedAsset(QueuedAsset<?> asset){
queuedAssetLock.lock();
lock.lock();
this.queuedAssets.add(asset);
//promise a specific string for this asset
@ -740,7 +825,7 @@ public class AssetManager {
asset.setPromisedPath(promisedPath);
}
queuedAssetLock.unlock();
lock.unlock();
return promisedPath;
}

View File

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

View File

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

View File

@ -6,8 +6,9 @@ import io.github.studiorailgun.CircularByteBuffer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedList;
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.
@ -37,12 +38,12 @@ public class NetworkParser {
/**
* 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
*/
CopyOnWriteArrayList<NetworkMessage> outgoingMessageQueue = new CopyOnWriteArrayList<NetworkMessage>();
LinkedList<NetworkMessage> outgoingMessageQueue = new LinkedList<NetworkMessage>();
/**
* Message object pool
@ -59,11 +60,6 @@ public class NetworkParser {
*/
byte[] readBuffer = new byte[READ_BLOCK_SIZE];
/**
* The outgoing byte buffer
*/
CopyOnWriteArrayList<Byte> outgoingByteQueue = new CopyOnWriteArrayList<Byte>();
/**
* The number of bytes read
*/
@ -75,6 +71,11 @@ public class NetworkParser {
*/
boolean releaseOnSend = true;
/**
* Lock for thread-safing the parser
*/
ReentrantLock lock = new ReentrantLock();
/**
* Constructor
@ -103,9 +104,11 @@ public class NetworkParser {
//parse byte queue for messages
//for each message, append to clientIncomingMessageQueue
NetworkMessage newMessage;
lock.lock();
while((newMessage = NetworkMessage.parseBytestreamForMessage(incomingByteBuffer,this.pool))!=null){
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
*/
public void pushMessagesOut() throws IOException {
lock.lock();
for(NetworkMessage message : outgoingMessageQueue){
outgoingMessageQueue.remove(message);
outgoingStream.write(message.getRawBytes());
if(this.releaseOnSend){
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
*/
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
*/
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
*/
public void addOutgoingMessage(NetworkMessage message){
lock.lock();
outgoingMessageQueue.add(message);
lock.unlock();
}
/**
@ -151,7 +164,9 @@ public class NetworkParser {
* @param messages The list to copy the incoming messages to
*/
public void copyIncomingMessages(List<NetworkMessage> messages){
lock.lock();
messages.addAll(incomingMessageQueue);
lock.unlock();
}
/**
@ -159,7 +174,9 @@ public class NetworkParser {
* @param messages The list to copy the outgoing messages to
*/
public void copyOutgoingMessages(List<NetworkMessage> messages){
lock.lock();
messages.addAll(outgoingMessageQueue);
lock.unlock();
}
/**

View File

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

View File

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

View File

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

View File

@ -1,8 +1,5 @@
package electrosphere.server.physics.terrain.generation;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.server.physics.terrain.generation.interfaces.ChunkGenerator;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
@ -19,7 +16,7 @@ public class OverworldChunkGenerator implements ChunkGenerator {
//cache for the bicubic interpolated chunks
//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
Map<String, float[][]> heightmapCache = new ConcurrentHashMap<String, float[][]>();
// Map<String, float[][]> heightmapCache = new ConcurrentHashMap<String, float[][]>();
/**
* Constructor