optimization work
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good

This commit is contained in:
austin 2025-03-29 20:23:17 -04:00
parent 5588827644
commit c630a184aa
19 changed files with 184 additions and 137 deletions

View File

@ -1383,6 +1383,7 @@ Network message object pooling
Threadsafe EntityDataCellMapper Threadsafe EntityDataCellMapper
Code cleanup Code cleanup
Small ServerAttackTree fix (for when not holding an item) Small ServerAttackTree fix (for when not holding an item)
Work on optimization

View File

@ -32,9 +32,14 @@ public class ChunkData {
*/ */
public static final int CHUNK_DATA_SIZE = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE; public static final int CHUNK_DATA_SIZE = ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE;
//What type of terrain is in this voxel, eg stone vs dirt vs grass, etc /**
* What type of terrain is in this voxel, eg stone vs dirt vs grass, etc
*/
int[][][] voxelType; int[][][] voxelType;
//How much of that terrain type is in this voxel
/**
* How much of that terrain type is in this voxel
*/
float[][][] voxelWeight; float[][][] voxelWeight;
//the list of positions modified since the last call to resetModifiedPositions //the list of positions modified since the last call to resetModifiedPositions

View File

@ -112,7 +112,6 @@ public class ClientTerrainManager {
public void handleMessages(){ public void handleMessages(){
Globals.profiler.beginCpuSample("ClientTerrainManager.handleMessages"); Globals.profiler.beginCpuSample("ClientTerrainManager.handleMessages");
lock.acquireUninterruptibly(); lock.acquireUninterruptibly();
List<TerrainMessage> bouncedMessages = new LinkedList<TerrainMessage>();
for(TerrainMessage message : messageQueue){ for(TerrainMessage message : messageQueue){
switch(message.getMessageSubtype()){ switch(message.getMessageSubtype()){
case SENDCHUNKDATA: { case SENDCHUNKDATA: {
@ -216,11 +215,9 @@ public class ClientTerrainManager {
LoggerInterface.loggerEngine.WARNING("ClientTerrainManager: unhandled network message of type" + message.getMessageSubtype()); LoggerInterface.loggerEngine.WARNING("ClientTerrainManager: unhandled network message of type" + message.getMessageSubtype());
break; break;
} }
Globals.clientConnection.release(message);
} }
messageQueue.clear(); messageQueue.clear();
for(TerrainMessage message : bouncedMessages){
messageQueue.add(message);
}
//evaluate if any terrain chunks have failed to request //evaluate if any terrain chunks have failed to request
for(Long key : this.requestedMap.keySet()){ for(Long key : this.requestedMap.keySet()){
int duration = this.requestedMap.get(key); int duration = this.requestedMap.get(key);

View File

@ -4,8 +4,8 @@ import electrosphere.entity.Entity;
import electrosphere.entity.state.collidable.Impulse; import electrosphere.entity.state.collidable.Impulse;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/** /**
@ -22,7 +22,7 @@ public class Collidable {
boolean parentTracksCollidable = true; boolean parentTracksCollidable = true;
//The impulses to be applied to this collidable //The impulses to be applied to this collidable
List<Impulse> impulses = new CopyOnWriteArrayList<Impulse>(); List<Impulse> impulses = new LinkedList<Impulse>();
/** /**
* The params for the surface of this collidable when a collision occurs * The params for the surface of this collidable when a collision occurs

View File

@ -47,10 +47,10 @@ public class EntityUtils {
if(dataCell != null){ if(dataCell != null){
dataCell.getScene().deregisterEntity(e); dataCell.getScene().deregisterEntity(e);
} }
Globals.entityDataCellMapper.ejectEntity(e);
} }
Globals.realmManager.removeEntity(e); Globals.realmManager.removeEntity(e);
} }
Globals.entityDataCellMapper.ejectEntity(e);
EntityLookupUtils.removeEntity(e); EntityLookupUtils.removeEntity(e);
} }

View File

@ -6,15 +6,17 @@ import electrosphere.entity.EntityTags;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.attach.AttachUtils; import electrosphere.entity.state.attach.AttachUtils;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.util.annotation.Exclude;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List; import java.util.List;
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.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
/** /**
* A game scene * A game scene
@ -36,32 +38,38 @@ public class Scene {
*/ */
List<BehaviorTree> behaviorTreeList; List<BehaviorTree> behaviorTreeList;
@Exclude
/**
* Lock for threadsafeing the scene
*/
ReentrantLock lock = new ReentrantLock();
/** /**
* Constructor * Constructor
*/ */
public Scene(){ public Scene(){
entityIdMap = new ConcurrentHashMap<Integer,Entity>(); entityIdMap = new HashMap<Integer,Entity>();
tagEntityMap = new ConcurrentHashMap<String,Set<Entity>>(); tagEntityMap = new HashMap<String,Set<Entity>>();
behaviorTreeList = new CopyOnWriteArrayList<BehaviorTree>(); behaviorTreeList = new LinkedList<BehaviorTree>();
tagEntityMap.put(EntityTags.BONE_ATTACHED, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.BONE_ATTACHED, new HashSet<Entity>());
tagEntityMap.put(EntityTags.COLLIDABLE, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.COLLIDABLE, new HashSet<Entity>());
tagEntityMap.put(EntityTags.SPRINTABLE, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.SPRINTABLE, new HashSet<Entity>());
tagEntityMap.put(EntityTags.MOVEABLE, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.MOVEABLE, new HashSet<Entity>());
tagEntityMap.put(EntityTags.ATTACKER, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.ATTACKER, new HashSet<Entity>());
tagEntityMap.put(EntityTags.TARGETABLE, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.TARGETABLE, new HashSet<Entity>());
tagEntityMap.put(EntityTags.LIFE_STATE, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.LIFE_STATE, new HashSet<Entity>());
tagEntityMap.put(EntityTags.CREATURE, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.CREATURE, new HashSet<Entity>());
tagEntityMap.put(EntityTags.UI, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.UI, new HashSet<Entity>());
tagEntityMap.put(EntityTags.DRAWABLE, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.DRAWABLE, new HashSet<Entity>());
tagEntityMap.put(EntityTags.DRAW_INSTANCED, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.DRAW_INSTANCED, new HashSet<Entity>());
tagEntityMap.put(EntityTags.DRAW_VOLUMETIC_SOLIDS_PASS, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.DRAW_VOLUMETIC_SOLIDS_PASS, new HashSet<Entity>());
tagEntityMap.put(EntityTags.DRAW_VOLUMETIC_DEPTH_PASS, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.DRAW_VOLUMETIC_DEPTH_PASS, new HashSet<Entity>());
tagEntityMap.put(EntityTags.DRAW_CAST_SHADOW, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.DRAW_CAST_SHADOW, new HashSet<Entity>());
tagEntityMap.put(EntityTags.LIGHT, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.LIGHT, new HashSet<Entity>());
tagEntityMap.put(EntityTags.ITEM, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.ITEM, new HashSet<Entity>());
tagEntityMap.put(EntityTags.GRAVITY, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.GRAVITY, new HashSet<Entity>());
tagEntityMap.put(EntityTags.PARTICLE, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.PARTICLE, new HashSet<Entity>());
tagEntityMap.put(EntityTags.TRANSFORM_ATTACHED, new CopyOnWriteArraySet<Entity>()); tagEntityMap.put(EntityTags.TRANSFORM_ATTACHED, new HashSet<Entity>());
} }
/** /**
@ -69,7 +77,9 @@ public class Scene {
* @param e The entity to register * @param e The entity to register
*/ */
public void registerEntity(Entity e){ public void registerEntity(Entity e){
lock.lock();
entityIdMap.put(e.getId(), e); entityIdMap.put(e.getId(), e);
lock.unlock();
} }
/** /**
@ -78,13 +88,15 @@ public class Scene {
* @param tag The tag * @param tag The tag
*/ */
public void registerEntityToTag(Entity e, String tag){ public void registerEntityToTag(Entity e, String tag){
lock.lock();
if(tagEntityMap.containsKey(tag)){ if(tagEntityMap.containsKey(tag)){
tagEntityMap.get(tag).add(e); tagEntityMap.get(tag).add(e);
} else { } else {
Set<Entity> newEntityList = new CopyOnWriteArraySet<Entity>(); Set<Entity> newEntityList = new HashSet<Entity>();
newEntityList.add(e); newEntityList.add(e);
tagEntityMap.put(tag,newEntityList); tagEntityMap.put(tag,newEntityList);
} }
lock.unlock();
} }
/** /**
@ -93,7 +105,13 @@ public class Scene {
* @return A list of all entities with the tag, or null if no entities have been added to the tag yet * @return A list of all entities with the tag, or null if no entities have been added to the tag yet
*/ */
public Set<Entity> getEntitiesWithTag(String tag){ public Set<Entity> getEntitiesWithTag(String tag){
return tagEntityMap.get(tag); lock.lock();
Set<Entity> rVal = null;
if(tagEntityMap.containsKey(tag)){
rVal = new HashSet<Entity>(tagEntityMap.get(tag));
}
lock.unlock();
return rVal;
} }
/** /**
@ -102,7 +120,9 @@ public class Scene {
* @param tag The tag * @param tag The tag
*/ */
public void removeEntityFromTag(Entity e, String tag){ public void removeEntityFromTag(Entity e, String tag){
lock.lock();
tagEntityMap.get(tag).remove(e); tagEntityMap.get(tag).remove(e);
lock.unlock();
} }
/** /**
@ -110,10 +130,12 @@ public class Scene {
* @param e * @param e
*/ */
public void deregisterEntity(Entity e){ public void deregisterEntity(Entity e){
lock.lock();
for(String key : tagEntityMap.keySet()){ for(String key : tagEntityMap.keySet()){
tagEntityMap.get(key).remove(e); tagEntityMap.get(key).remove(e);
} }
entityIdMap.remove(e.getId()); entityIdMap.remove(e.getId());
lock.unlock();
} }
/** /**
@ -121,6 +143,7 @@ public class Scene {
* @param target The top level entity to deregister * @param target The top level entity to deregister
*/ */
public void recursiveDeregister(Entity target){ public void recursiveDeregister(Entity target){
lock.lock();
if(AttachUtils.hasChildren(target)){ if(AttachUtils.hasChildren(target)){
List<Entity> childrenList = AttachUtils.getChildrenList(target); List<Entity> childrenList = AttachUtils.getChildrenList(target);
for(Entity currentChild : childrenList){ for(Entity currentChild : childrenList){
@ -128,6 +151,7 @@ public class Scene {
} }
} }
this.deregisterEntity(target); this.deregisterEntity(target);
lock.unlock();
} }
/** /**
@ -136,7 +160,10 @@ public class Scene {
* @return The entity with that ID * @return The entity with that ID
*/ */
public Entity getEntityFromId(int id){ public Entity getEntityFromId(int id){
return (Entity)entityIdMap.get(id); lock.lock();
Entity rVal = (Entity)entityIdMap.get(id);
lock.unlock();
return rVal;
} }
/** /**
@ -145,7 +172,10 @@ public class Scene {
* @return true if the scene contains the entity, false otherwise * @return true if the scene contains the entity, false otherwise
*/ */
public boolean containsEntity(Entity e){ public boolean containsEntity(Entity e){
return entityIdMap.containsKey(e.getId()); lock.lock();
boolean rVal = entityIdMap.containsKey(e.getId());
lock.unlock();
return rVal;
} }
/** /**
@ -153,7 +183,9 @@ public class Scene {
* @param tree The behavior tree to register * @param tree The behavior tree to register
*/ */
public void registerBehaviorTree(BehaviorTree tree){ public void registerBehaviorTree(BehaviorTree tree){
lock.lock();
behaviorTreeList.add(tree); behaviorTreeList.add(tree);
lock.unlock();
} }
/** /**
@ -161,9 +193,11 @@ public class Scene {
* @param task The task * @param task The task
*/ */
public void registerBehaviorTree(Runnable task){ public void registerBehaviorTree(Runnable task){
lock.lock();
this.registerBehaviorTree(new BehaviorTree(){public void simulate(float deltaTime) { this.registerBehaviorTree(new BehaviorTree(){public void simulate(float deltaTime) {
task.run(); task.run();
}}); }});
lock.unlock();
} }
/** /**
@ -171,20 +205,25 @@ public class Scene {
* @param tree The behavior tree to deregister * @param tree The behavior tree to deregister
*/ */
public void deregisterBehaviorTree(BehaviorTree tree){ public void deregisterBehaviorTree(BehaviorTree tree){
lock.lock();
while(behaviorTreeList.contains(tree)){ while(behaviorTreeList.contains(tree)){
behaviorTreeList.remove(tree); behaviorTreeList.remove(tree);
} }
lock.unlock();
} }
/** /**
* Simulates all behavior trees stored in the entity manager * Simulates all behavior trees stored in the entity manager
*/ */
public void simulateBehaviorTrees(float deltaTime){ public void simulateBehaviorTrees(float deltaTime){
lock.lock();
Globals.profiler.beginAggregateCpuSample("Scene.simulateBehaviorTrees"); Globals.profiler.beginAggregateCpuSample("Scene.simulateBehaviorTrees");
for(BehaviorTree tree : behaviorTreeList){ List<BehaviorTree> trees = new LinkedList<BehaviorTree>(behaviorTreeList);
for(BehaviorTree tree : trees){
tree.simulate(deltaTime); tree.simulate(deltaTime);
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
lock.unlock();
} }
/** /**
@ -192,7 +231,10 @@ public class Scene {
* @return The collection of all entities in the scene * @return The collection of all entities in the scene
*/ */
public Collection<Entity> getEntityList(){ public Collection<Entity> getEntityList(){
return this.entityIdMap.values(); lock.lock();
Collection<Entity> rVal = new LinkedList<Entity>(this.entityIdMap.values());
lock.unlock();
return rVal;
} }
/** /**
@ -200,7 +242,10 @@ public class Scene {
* @return The list of behavior trees attached to the scene * @return The list of behavior trees attached to the scene
*/ */
public Collection<BehaviorTree> getBehaviorTrees(){ public Collection<BehaviorTree> getBehaviorTrees(){
return Collections.unmodifiableList(this.behaviorTreeList); lock.lock();
Collection<BehaviorTree> rVal = new LinkedList<BehaviorTree>(this.behaviorTreeList);
lock.unlock();
return rVal;
} }
/** /**

View File

@ -41,7 +41,6 @@ import electrosphere.server.datacell.Realm;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Vector3d; import org.joml.Vector3d;
@ -63,7 +62,7 @@ public class ServerAttackTree implements BehaviorTree {
Entity parent; Entity parent;
CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>(); List<EntityMessage> networkMessageQueue = new LinkedList<EntityMessage>();
long lastUpdateTime = 0; long lastUpdateTime = 0;
@ -370,10 +369,12 @@ public class ServerAttackTree implements BehaviorTree {
this.stateTransitionUtil.simulate(AttackTreeState.ATTACK); this.stateTransitionUtil.simulate(AttackTreeState.ATTACK);
//activate hitboxes //activate hitboxes
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent); List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){ if(attachedEntities != null){
if(HitboxCollectionState.hasHitboxState(currentAttached)){ for(Entity currentAttached : attachedEntities){
HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached); if(HitboxCollectionState.hasHitboxState(currentAttached)){
currentState.setActive(true); HitboxCollectionState currentState = HitboxCollectionState.getHitboxState(currentAttached);
currentState.setActive(true);
}
} }
} }
if(firesProjectile && projectileToFire != null){ if(firesProjectile && projectileToFire != null){

View File

@ -23,7 +23,8 @@ import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.server.poseactor.PoseActor; import electrosphere.server.poseactor.PoseActor;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.LinkedList;
import java.util.List;
@SynchronizedBehaviorTree(name = "serverIdle", isServer = true, correspondingTree = "idle") @SynchronizedBehaviorTree(name = "serverIdle", isServer = true, correspondingTree = "idle")
@ -40,7 +41,7 @@ public class ServerIdleTree implements BehaviorTree {
//The idle data //The idle data
IdleData idleData; IdleData idleData;
CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>(); List<EntityMessage> networkMessageQueue = new LinkedList<EntityMessage>();
/** /**
* Creates a server idle tree * Creates a server idle tree

View File

@ -1,6 +1,7 @@
package electrosphere.entity.state.inventory; package electrosphere.entity.state.inventory;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.LinkedList;
import java.util.List;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
@ -19,7 +20,7 @@ public class ServerInventoryState implements BehaviorTree {
/** /**
* The queue of messages to handle * The queue of messages to handle
*/ */
CopyOnWriteArrayList<InventoryMessage> networkMessageQueue = new CopyOnWriteArrayList<InventoryMessage>(); List<InventoryMessage> networkMessageQueue = new LinkedList<InventoryMessage>();
/** /**
* The parent of the state * The parent of the state

View File

@ -31,7 +31,8 @@ import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.server.utils.ServerScriptUtils; import electrosphere.server.utils.ServerScriptUtils;
import electrosphere.util.math.SpatialMathUtils; import electrosphere.util.math.SpatialMathUtils;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.LinkedList;
import java.util.List;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Vector3d; import org.joml.Vector3d;
@ -63,7 +64,7 @@ public class ServerEditorMovementTree implements BehaviorTree {
Entity parent; Entity parent;
CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>(); List<EntityMessage> networkMessageQueue = new LinkedList<EntityMessage>();
long lastUpdateTime = 0; long lastUpdateTime = 0;

View File

@ -35,7 +35,8 @@ import electrosphere.server.poseactor.PoseActor;
import electrosphere.server.utils.ServerScriptUtils; import electrosphere.server.utils.ServerScriptUtils;
import electrosphere.util.math.SpatialMathUtils; import electrosphere.util.math.SpatialMathUtils;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.LinkedList;
import java.util.List;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Vector3d; import org.joml.Vector3d;
@ -71,7 +72,7 @@ public class ServerGroundMovementTree implements BehaviorTree {
Collidable collidable; Collidable collidable;
CopyOnWriteArrayList<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>(); List<EntityMessage> networkMessageQueue = new LinkedList<EntityMessage>();
long lastUpdateTime = 0; long lastUpdateTime = 0;

View File

@ -69,6 +69,12 @@ public class NetworkParser {
*/ */
long totalBytesRead = 0; long totalBytesRead = 0;
/**
* If set to true, the parser will automatically release messages on send.
* Otherwise, will not release when the message is sent.
*/
boolean releaseOnSend = true;
/** /**
* Constructor * Constructor
@ -110,7 +116,9 @@ public class NetworkParser {
for(NetworkMessage message : outgoingMessageQueue){ for(NetworkMessage message : outgoingMessageQueue){
outgoingMessageQueue.remove(message); outgoingMessageQueue.remove(message);
outgoingStream.write(message.getRawBytes()); outgoingStream.write(message.getRawBytes());
this.pool.release(message); if(this.releaseOnSend){
this.pool.release(message);
}
} }
} }
@ -178,4 +186,13 @@ public class NetworkParser {
return this.pool; return this.pool;
} }
/**
* If set to true, the parser will automatically release messages on send.
* Otherwise, will not release when the message is sent.
* @param releaseOnSend true to release messages on send, false otherwise
*/
public void setReleaseOnSend(boolean releaseOnSend){
this.releaseOnSend = releaseOnSend;
}
} }

View File

@ -129,6 +129,7 @@ public class ServerConnectionHandler implements Runnable {
if(this.local){ if(this.local){
//run if serverconnectionHandler is created by passing in input/output streams //run if serverconnectionHandler is created by passing in input/output streams
networkParser = new NetworkParser(inputStream,outputStream); networkParser = new NetworkParser(inputStream,outputStream);
networkParser.setReleaseOnSend(false);
messageProtocol = new MessageProtocol(this); messageProtocol = new MessageProtocol(this);
} else { } else {
//run if ServerConnectionHandler is created by passing in a socket //run if ServerConnectionHandler is created by passing in a socket

View File

@ -7,7 +7,6 @@ import electrosphere.logger.LoggerInterface;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.state.movement.jump.ServerJumpTree; import electrosphere.entity.state.movement.jump.ServerJumpTree;
@ -33,7 +32,7 @@ public class ServerSynchronizationManager {
//The list of messages to loop through //The list of messages to loop through
List<SynchronizationMessage> messages = new CopyOnWriteArrayList<SynchronizationMessage>(); List<SynchronizationMessage> messages = new LinkedList<SynchronizationMessage>();
/** /**
* Pushes a message into the queue to be processed * Pushes a message into the queue to be processed

View File

@ -1,9 +1,9 @@
package electrosphere.server.datacell; package electrosphere.server.datacell;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import org.joml.Vector3d; import org.joml.Vector3d;
@ -26,11 +26,19 @@ import electrosphere.server.fluid.simulator.FluidAcceleratedSimulator;
*/ */
public class RealmManager { public class RealmManager {
//All realms in this manager /**
Set<Realm> realms = new CopyOnWriteArraySet<Realm>(); * All realms in this manager
//Map of entities to the realm the entity is in */
Set<Realm> realms = new HashSet<Realm>();
/**
* Map of entities to the realm the entity is in
*/
Map<Entity,Realm> entityToRealmMap = new HashMap<Entity,Realm>(); Map<Entity,Realm> entityToRealmMap = new HashMap<Entity,Realm>();
//Map of player to the realm the player is in
/**
* Map of player to the realm the player is in
*/
Map<Player,Realm> playerToRealmMap = new HashMap<Player,Realm>(); Map<Player,Realm> playerToRealmMap = new HashMap<Player,Realm>();
/** /**
@ -165,7 +173,10 @@ public class RealmManager {
* @return The set containing all realms in the manager * @return The set containing all realms in the manager
*/ */
public Set<Realm> getRealms(){ public Set<Realm> getRealms(){
return realms; lock.lock();
Set<Realm> rVal = new HashSet<Realm>(realms);
lock.unlock();
return rVal;
} }
@ -174,6 +185,7 @@ public class RealmManager {
*/ */
public void simulate(){ public void simulate(){
Globals.profiler.beginCpuSample("RealmManager.simulate"); Globals.profiler.beginCpuSample("RealmManager.simulate");
Set<Realm> realms = this.getRealms();
for(Realm realm : realms){ for(Realm realm : realms){
realm.simulate(); realm.simulate();
} }
@ -209,6 +221,7 @@ public class RealmManager {
* @param saveName The name of the save * @param saveName The name of the save
*/ */
public void save(String saveName){ public void save(String saveName){
Set<Realm> realms = this.getRealms();
for(Realm realm : realms){ for(Realm realm : realms){
realm.save(saveName); realm.save(saveName);
} }

View File

@ -52,8 +52,10 @@ public class GriddedDataCellLoaderService {
//let the service know we've finished this job //let the service know we've finished this job
lock.lock(); lock.lock();
queuedWorkLock.remove(key); queuedWorkLock.remove(key);
jobOperationMap.remove(key);
lock.unlock(); lock.unlock();
}; };
jobOperationMap.put(key,operation);
if(job != null){ if(job != null){
if(!job.cancel(false)){ if(!job.cancel(false)){
try { try {
@ -69,80 +71,24 @@ public class GriddedDataCellLoaderService {
if(job.isCancelled()){ if(job.isCancelled()){
Runnable oldOp = jobOperationMap.remove(key); Runnable oldOp = jobOperationMap.remove(key);
//queue job to run the old operation first, then the new one //queue job to run the old operation first, then the new one
opCallback = () -> { Runnable currentOp = () -> {
oldOp.run(); oldOp.run();
//load here
operation.run(); operation.run();
};
opCallback = () -> {
currentOp.run();
//let the service know we've finished this job //let the service know we've finished this job
lock.lock(); lock.lock();
queuedWorkLock.remove(key); queuedWorkLock.remove(key);
jobOperationMap.remove(key);
lock.unlock(); lock.unlock();
}; };
jobOperationMap.put(key,currentOp);
} }
} }
//queue job to do the operation //queue job to do the operation
Future<?> newJob = ioThreadService.submit(opCallback); Future<?> newJob = ioThreadService.submit(opCallback);
queuedWorkLock.put(key, newJob); queuedWorkLock.put(key, newJob);
jobOperationMap.put(key,operation);
lock.unlock();
}
/**
* Loads a cell
* @param key The key for the cell
*/
protected static void loadCell(long key, Runnable loadLogic){
lock.lock();
//if there is a job queued and we couldn't cancel it, wait
Future<?> job = queuedWorkLock.get(key);
if(job != null && !job.cancel(false)){
try {
Globals.profiler.beginCpuSample("Waiting for cell io job to finish");
job.wait();
Globals.profiler.endCpuSample();
} catch (InterruptedException e) {
LoggerInterface.loggerEngine.ERROR("Failed to wait for previous job for cell!", e);
}
}
//queue job to load the cell
Future<?> newJob = ioThreadService.submit(() -> {
//load here
loadLogic.run();
//let the service know we've finished this job
lock.lock();
queuedWorkLock.remove(key);
lock.unlock();
});
queuedWorkLock.put(key, newJob);
lock.unlock();
}
/**
* Unloads a cell
* @param key The key for the cell
*/
protected static void unloadCell(long key, Runnable unloadLogic){
lock.lock();
//if there is a job queued and we couldn't cancel it, wait
Future<?> job = queuedWorkLock.get(key);
if(job != null && !job.cancel(false)){
try {
Globals.profiler.beginCpuSample("Waiting for cell io job to finish");
job.wait();
Globals.profiler.endCpuSample();
} catch (InterruptedException e) {
LoggerInterface.loggerEngine.ERROR("Failed to wait for previous job for cell!", e);
}
}
//queue job to load the cell
ioThreadService.submit(() -> {
//unload here
unloadLogic.run();
//let the service know we've finished this job
lock.lock();
queuedWorkLock.remove(key);
lock.unlock();
});
lock.unlock(); lock.unlock();
} }

View File

@ -296,10 +296,12 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
*/ */
private void createTerrainPhysicsEntities(Vector3i worldPos){ private void createTerrainPhysicsEntities(Vector3i worldPos){
Long key = this.getServerDataCellKey(worldPos); Long key = this.getServerDataCellKey(worldPos);
loadedCellsLock.lock();
if(posPhysicsMap.containsKey(key)){ if(posPhysicsMap.containsKey(key)){
PhysicsDataCell cell = posPhysicsMap.get(key); PhysicsDataCell cell = posPhysicsMap.get(key);
cell.retireCell(); cell.retireCell();
} }
loadedCellsLock.unlock();
//get data to generate with //get data to generate with
Vector3d realPos = new Vector3d( Vector3d realPos = new Vector3d(
worldPos.x * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET, worldPos.x * ServerTerrainChunk.CHUNK_PLACEMENT_OFFSET,
@ -325,7 +327,9 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
cell.setTerrainChunk(terrainChunk); cell.setTerrainChunk(terrainChunk);
cell.setBlockChunk(blockChunkData); cell.setBlockChunk(blockChunkData);
cell.generatePhysics(); cell.generatePhysics();
loadedCellsLock.lock();
posPhysicsMap.put(key, cell); posPhysicsMap.put(key, cell);
loadedCellsLock.unlock();
} }
/** /**
@ -742,8 +746,10 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
serverContentManager.generateContentForDataCell(parent, worldPos, rVal, cellKey); serverContentManager.generateContentForDataCell(parent, worldPos, rVal, cellKey);
}); });
//generates physics for the cell in a dedicated thread then finally registers //generates physics for the cell in a dedicated thread then finally registers
loadedCellsLock.lock();
PhysicsDataCell cell = posPhysicsMap.get(key); PhysicsDataCell cell = posPhysicsMap.get(key);
GriddedDataCellManager.runPhysicsGenerationThread(worldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.parent); GriddedDataCellManager.runPhysicsGenerationThread(worldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.parent);
loadedCellsLock.unlock();
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();

View File

@ -4,6 +4,7 @@ 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.locks.ReentrantLock;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.btree.BehaviorTree; import electrosphere.entity.btree.BehaviorTree;
@ -17,14 +18,24 @@ import electrosphere.server.datacell.ServerDataCell;
*/ */
public class ServerBehaviorTreeUtils { public class ServerBehaviorTreeUtils {
/**
* The map of entity to set of behavior trees attached to it
*/
static Map<Entity,Set<BehaviorTree>> entityBTreeMap = new HashMap<Entity,Set<BehaviorTree>>(); static Map<Entity,Set<BehaviorTree>> entityBTreeMap = new HashMap<Entity,Set<BehaviorTree>>();
/**
* Lock for thread-safeing the util
*/
static ReentrantLock lock = new ReentrantLock();
/** /**
* Tracks behavior trees attached to this entity * Tracks behavior trees attached to this entity
* @param entity * @param entity
*/ */
public static void registerEntity(Entity entity){ public static void registerEntity(Entity entity){
lock.lock();
entityBTreeMap.put(entity, new HashSet<BehaviorTree>()); entityBTreeMap.put(entity, new HashSet<BehaviorTree>());
lock.unlock();
} }
/** /**
@ -32,6 +43,7 @@ public class ServerBehaviorTreeUtils {
* @param entity * @param entity
*/ */
public static void deregisterEntity(Entity entity){ public static void deregisterEntity(Entity entity){
lock.lock();
Set<BehaviorTree> trees = entityBTreeMap.remove(entity); Set<BehaviorTree> trees = entityBTreeMap.remove(entity);
ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity); ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity);
if(trees != null){ if(trees != null){
@ -39,6 +51,7 @@ public class ServerBehaviorTreeUtils {
currentCell.getScene().deregisterBehaviorTree(tree); currentCell.getScene().deregisterBehaviorTree(tree);
} }
} }
lock.unlock();
} }
/** /**
@ -47,10 +60,12 @@ public class ServerBehaviorTreeUtils {
* @param behaviorTree The behavior tree * @param behaviorTree The behavior tree
*/ */
public static void attachBTreeToEntity(Entity entity, BehaviorTree behaviorTree){ public static void attachBTreeToEntity(Entity entity, BehaviorTree behaviorTree){
lock.lock();
entityBTreeMap.get(entity).add(behaviorTree); entityBTreeMap.get(entity).add(behaviorTree);
//register to cell //register to cell
ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity); ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity);
currentCell.getScene().registerBehaviorTree(behaviorTree); currentCell.getScene().registerBehaviorTree(behaviorTree);
lock.unlock();
} }
/** /**
@ -59,10 +74,12 @@ public class ServerBehaviorTreeUtils {
* @param behaviorTree The behavior tree * @param behaviorTree The behavior tree
*/ */
public static void detatchBTreeFromEntity(Entity entity, BehaviorTree behaviorTree){ public static void detatchBTreeFromEntity(Entity entity, BehaviorTree behaviorTree){
lock.lock();
entityBTreeMap.get(entity).remove(behaviorTree); entityBTreeMap.get(entity).remove(behaviorTree);
//deregister from cell //deregister from cell
ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity); ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity);
currentCell.getScene().deregisterBehaviorTree(behaviorTree); currentCell.getScene().deregisterBehaviorTree(behaviorTree);
lock.unlock();
} }
@ -72,6 +89,7 @@ public class ServerBehaviorTreeUtils {
* @param oldCell The cell the entity used to inhabit * @param oldCell The cell the entity used to inhabit
*/ */
public static void updateCell(Entity entity, ServerDataCell oldCell){ public static void updateCell(Entity entity, ServerDataCell oldCell){
lock.lock();
Set<BehaviorTree> trees = entityBTreeMap.get(entity); Set<BehaviorTree> trees = entityBTreeMap.get(entity);
ServerDataCell newCell = DataCellSearchUtils.getEntityDataCell(entity); ServerDataCell newCell = DataCellSearchUtils.getEntityDataCell(entity);
if(trees != null){ if(trees != null){
@ -82,6 +100,7 @@ public class ServerBehaviorTreeUtils {
newCell.getScene().registerBehaviorTree(tree); newCell.getScene().registerBehaviorTree(tree);
} }
} }
lock.unlock();
} }
} }

View File

@ -1,9 +1,5 @@
package electrosphere.server.saves; package electrosphere.server.saves;
import java.util.List;
import electrosphere.entity.scene.Scene;
/** /**
* Top level save object that stores information about the save * Top level save object that stores information about the save
*/ */
@ -24,9 +20,6 @@ public class Save {
//The name of the save //The name of the save
String name; String name;
//The scenes
List<Scene> scenes;
/** /**
* Constructor * Constructor
*/ */