work towards async entity creation on server
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
1c50468bdf
commit
028b957b76
@ -1356,6 +1356,7 @@ Grass height variance with control from ui + file
|
||||
Fix block mesh ray casting bug due to trimesh overlap
|
||||
Fix block mesh samplers incorrectly buffering
|
||||
Fix block mesh gen algorithm merging quads incorrectly
|
||||
Make HitboxManager threadsafe
|
||||
|
||||
|
||||
|
||||
|
||||
@ -4,19 +4,32 @@ import electrosphere.collision.CollisionEngine;
|
||||
import electrosphere.collision.CollisionEngine.CollisionResolutionCallback;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.state.hitbox.HitboxCollectionState;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Manages all hitboxes on either the server or client
|
||||
*/
|
||||
public class HitboxManager {
|
||||
|
||||
//the list of all hitboxes
|
||||
CopyOnWriteArrayList<HitboxCollectionState> hitboxes = new CopyOnWriteArrayList<HitboxCollectionState>();
|
||||
/**
|
||||
* The list of all hitboxes
|
||||
*/
|
||||
List<HitboxCollectionState> hitboxes = new LinkedList<HitboxCollectionState>();
|
||||
|
||||
//the collision engine for this hitbox manager
|
||||
/**
|
||||
* The collision engine for the hitbox manager
|
||||
*/
|
||||
CollisionEngine collisionEngine;
|
||||
|
||||
/**
|
||||
* Lock for hitbox collections
|
||||
*/
|
||||
ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
//an id incrementer for hitboxes
|
||||
long idIncrementer = 0;
|
||||
|
||||
@ -34,16 +47,21 @@ public class HitboxManager {
|
||||
* @param hitbox the hitbox to register
|
||||
*/
|
||||
public void registerHitbox(HitboxCollectionState hitbox){
|
||||
lock.lock();
|
||||
hitboxes.add(hitbox);
|
||||
idIncrementer++;
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all hitboxes in the manager
|
||||
* @return all hitboxes in the manager
|
||||
*/
|
||||
public CopyOnWriteArrayList<HitboxCollectionState> getAllHitboxes(){
|
||||
return hitboxes;
|
||||
public List<HitboxCollectionState> getAllHitboxes(){
|
||||
lock.lock();
|
||||
List<HitboxCollectionState> rVal = Collections.unmodifiableList(hitboxes);
|
||||
lock.unlock();
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,7 +69,9 @@ public class HitboxManager {
|
||||
* @param hitbox the hitbox to deregister
|
||||
*/
|
||||
public void deregisterHitbox(HitboxCollectionState hitbox){
|
||||
lock.lock();
|
||||
hitboxes.remove(hitbox);
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,10 +88,12 @@ public class HitboxManager {
|
||||
public void simulate(){
|
||||
//update all positions
|
||||
Globals.profiler.beginCpuSample("Update hitbox positions");
|
||||
lock.lock();
|
||||
for(HitboxCollectionState state : hitboxes){
|
||||
state.clearCollisions();
|
||||
state.updateHitboxPositions(this.collisionEngine);
|
||||
}
|
||||
lock.unlock();
|
||||
Globals.profiler.endCpuSample();
|
||||
//collide hitboxes
|
||||
Globals.profiler.beginCpuSample("Collide hitboxes");
|
||||
|
||||
@ -40,9 +40,11 @@ public class MainServerFunctions {
|
||||
if(Globals.realmManager != null){
|
||||
Globals.realmManager.simulate();
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
|
||||
//
|
||||
//Macro simulation (ie simulating the larger world macro data)
|
||||
Globals.profiler.beginCpuSample("MainServerFunctions.simulate - Server macro simulation");
|
||||
LoggerInterface.loggerEngine.DEBUG_LOOP("MainServerFunctions.simulate - Server macro simulation");
|
||||
if(Globals.macroSimulation != null && Globals.macroSimulation.isReady()){
|
||||
Globals.macroSimulation.simulate();
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
package electrosphere.server.datacell.gridded;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
|
||||
/**
|
||||
* Manages loading/unloading data cells for the gridded data cell manager
|
||||
*/
|
||||
public class GriddedDataCellLoaderService {
|
||||
|
||||
/**
|
||||
* Used for loading/unloading the cells
|
||||
*/
|
||||
protected static final ExecutorService ioThreadService = Executors.newFixedThreadPool(4);
|
||||
|
||||
/**
|
||||
* Lock for structures in this service
|
||||
*/
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
/**
|
||||
* Map of cell key -> job queued for that cell
|
||||
*/
|
||||
private static final Map<Long,Future<?>> queuedWorkLock = new HashMap<Long,Future<?>>();
|
||||
|
||||
/**
|
||||
* 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
|
||||
ioThreadService.submit(() -> {
|
||||
//load here
|
||||
loadLogic.run();
|
||||
//let the service know we've finished this job
|
||||
lock.lock();
|
||||
queuedWorkLock.remove(key);
|
||||
lock.unlock();
|
||||
});
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -422,8 +422,8 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Deconstruct timed out cells");
|
||||
this.numCleaned = toCleanQueue.size();
|
||||
for(ServerDataCell cell : toCleanQueue){
|
||||
//error check before actually queueing for deletion
|
||||
boolean containsPlayerEntity = false;
|
||||
//clear all entities in cell
|
||||
for(Entity entity : cell.getScene().getEntityList()){
|
||||
if(ServerPlayerViewDirTree.hasTree(entity)){
|
||||
containsPlayerEntity = true;
|
||||
@ -445,9 +445,10 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
if(containsPlayerEntity){
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Vector3i worldPos = this.getCellWorldPosition(cell);
|
||||
Long key = this.getServerDataCellKey(worldPos);
|
||||
|
||||
//offload all entities in cell to chunk file
|
||||
//entities are saved before tracking is removed. This makes sure that any side effects from calling destroyEntity (ie if it looks up the chunk that we're deleting)
|
||||
//don't trigger the chunk to be re-created
|
||||
@ -714,15 +715,22 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
Globals.profiler.beginCpuSample("GriddedDataCellManager.createServerDataCell");
|
||||
ServerDataCell rVal = parent.createNewCell();
|
||||
Long cellKey = this.getServerDataCellKey(worldPos);
|
||||
|
||||
loadedCellsLock.lock();
|
||||
groundDataCells.put(cellKey,rVal);
|
||||
cellPlayerlessFrameMap.put(rVal,0);
|
||||
LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + cellKey);
|
||||
cellPositionMap.put(rVal,new Vector3i(worldPos));
|
||||
loadedCellsLock.unlock();
|
||||
|
||||
//generate content
|
||||
serverContentManager.generateContentForDataCell(parent, worldPos, rVal, cellKey);
|
||||
//generates physics for the cell in a dedicated thread then finally registers
|
||||
Long key = this.getServerDataCellKey(worldPos);
|
||||
PhysicsDataCell cell = posPhysicsMap.get(key);
|
||||
GriddedDataCellManager.runPhysicsGenerationThread(worldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.parent);
|
||||
|
||||
|
||||
Globals.profiler.endCpuSample();
|
||||
return rVal;
|
||||
}
|
||||
@ -894,6 +902,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
*/
|
||||
public void halt(){
|
||||
generationService.shutdownNow();
|
||||
GriddedDataCellLoaderService.ioThreadService.shutdownNow();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Loading…
Reference in New Issue
Block a user