GriddedDataCellTrackingData + reduce allocs
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-04-04 16:34:13 -04:00
parent 86344ebfeb
commit 86c867fe31
4 changed files with 132 additions and 33 deletions

View File

@ -1432,6 +1432,11 @@ Fix PoseActor position/rotation caching bug
Bush drops sticks
Unarmed combat
(04/04/2025)
GriddedDataCellTrackingData created
Reduce allocations in GriddedDataCellManager methods that loop cells
Implement max distance for queueing for simulation

View File

@ -28,17 +28,25 @@ import java.util.Set;
*/
public class ServerDataCell {
//all players attached to this server data cell
/**
* All players attached to this server data cell
*/
Set<Player> activePlayers = new HashSet<Player>();
//the navmesh for the data cell
/**
* The navmesh for the data cell
*/
NavMesh navMesh;
//the scene backing the server data cell
/**
* The scene backing the server data cell
*/
Scene scene;
//controls whether the server data cell simulates its entities or not
boolean ready = false;
/**
* Controls whether the server data cell simulates its entities or not
*/
boolean ready = false;
/**
* Constructs a datacell based on a virtual cell. Should be used when a player
@ -50,6 +58,11 @@ public class ServerDataCell {
}
/**
* Creates a server data cell
* @param scene The scene to wrap the server data cell around
* @return The server data cell
*/
protected static ServerDataCell createServerDataCell(Scene scene){
return new ServerDataCell(scene);
}
@ -120,10 +133,10 @@ public class ServerDataCell {
for(Player player : this.activePlayers){
if(previousCell != null){
if(!previousCell.containsPlayer(player)){
serializeEntityToPlayer(creature,player);
this.serializeEntityToPlayer(creature,player);
}
} else {
serializeEntityToPlayer(creature,player);
this.serializeEntityToPlayer(creature,player);
}
}
}
@ -143,7 +156,7 @@ public class ServerDataCell {
* @param entity The entity to serialize
* @param player The player to send the entity to
*/
void serializeEntityToPlayer(Entity entity, Player player){
private void serializeEntityToPlayer(Entity entity, Player player){
if(!player.hasSentPlayerEntity() || player.getPlayerEntity() == null || player.getPlayerEntity() != entity){
EntityType type = CommonEntityUtils.getEntityType(entity);
if(type != null){

View File

@ -64,6 +64,11 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
*/
static final int UNLOAD_FRAME_THRESHOLD = 100;
/**
* The distance at which simulation is queued
*/
static final double SIMULATION_DISTANCE_CUTOFF = 5;
/**
* Used for generating physics chunks
*/
@ -89,6 +94,11 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
*/
Map<ServerDataCell,Integer> cellPlayerlessFrameMap = new HashMap<ServerDataCell,Integer>();
/**
* A map of ServerDataCell->GriddedDataCellTrackingData
*/
Map<ServerDataCell,GriddedDataCellTrackingData> cellTrackingMap = new HashMap<ServerDataCell,GriddedDataCellTrackingData>();
/**
* Loaded cells
*/
@ -178,21 +188,23 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
Globals.realmManager.setPlayerRealm(player, parent);
int playerSimulationRadius = player.getSimulationRadius();
Vector3i worldPos = player.getWorldPos();
Vector3i tempVec = new Vector3i();
for(int x = worldPos.x - playerSimulationRadius; x < worldPos.x + playerSimulationRadius + 1; x++){
for(int y = worldPos.y - playerSimulationRadius; y < worldPos.y + playerSimulationRadius + 1; y++){
for(int z = worldPos.z - playerSimulationRadius; z < worldPos.z + playerSimulationRadius + 1; z++){
if(this.canCreateCell(x, y, z) && this.shouldContainPlayer(new Vector3i(x,y,z), worldPos, playerSimulationRadius)){
Vector3i targetPos = new Vector3i(x,y,z);
tempVec.set(x,y,z);
double distance = this.calcDistance(tempVec, worldPos);
if(this.canCreateCell(x, y, z) && this.shouldContainPlayer(distance, playerSimulationRadius)){
LoggerInterface.loggerEngine.DEBUG("GriddedDataCellManager: Add player to " + x + " " + y + " " + z);
loadedCellsLock.lock();
if(groundDataCells.get(getServerDataCellKey(targetPos)) != null){
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
if(groundDataCells.get(this.getServerDataCellKey(tempVec)) != null){
groundDataCells.get(this.getServerDataCellKey(tempVec)).addPlayer(player);
} else {
LoggerInterface.loggerEngine.DEBUG("Creating new cell @ " + x + " " + y + " " + z);
//create data cell
this.createServerDataCell(targetPos);
this.createServerDataCell(tempVec);
//add player
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
groundDataCells.get(this.getServerDataCellKey(tempVec)).addPlayer(player);
}
loadedCellsLock.unlock();
}
@ -211,7 +223,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
player.setWorldPos(newPosition);
for(ServerDataCell cell : this.groundDataCells.values()){
Vector3i worldPos = this.getCellWorldPosition(cell);
if(cell.containsPlayer(player) && !this.shouldContainPlayer(worldPos, newPosition, playerSimulationRadius)){
if(cell.containsPlayer(player) && !this.shouldContainPlayer(this.calcDistance(worldPos, newPosition), playerSimulationRadius)){
cell.removePlayer(player);
this.broadcastDestructionToPlayer(player, cell);
if(cell.getScene().containsEntity(player.getPlayerEntity())){
@ -228,7 +240,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
for(int x = newPosition.x - playerSimulationRadius; x < newPosition.x + playerSimulationRadius + 1; x++){
for(int y = newPosition.y - playerSimulationRadius; y < newPosition.y + playerSimulationRadius + 1; y++){
for(int z = newPosition.x - playerSimulationRadius; z < newPosition.z + playerSimulationRadius + 1; z++){
if(this.canCreateCell(x, y, z) && this.shouldContainPlayer(new Vector3i(x, y, z), newPosition, playerSimulationRadius)){
if(this.canCreateCell(x, y, z) && this.shouldContainPlayer(this.calcDistance(new Vector3i(x, y, z), newPosition), playerSimulationRadius)){
Vector3i targetPos = new Vector3i(x,y,z);
if(groundDataCells.get(this.getServerDataCellKey(targetPos)) != null){
loadedCellsLock.lock();
@ -255,8 +267,18 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
* @param simRadius The simulation radius of the player
* @return true if the player should be contained in the cell, false otherwise
*/
private boolean shouldContainPlayer(Vector3i cellWorldPos, Vector3i playerPos, int simRadius){
return cellWorldPos.distance(playerPos) < simRadius;
private boolean shouldContainPlayer(double distance, int simRadius){
return distance < simRadius;
}
/**
* Calculates the distance from the player to the cell
* @param playerPos The player
* @param cellWorldPos The cell
* @return The distance
*/
public double calcDistance(Vector3i playerPos, Vector3i cellWorldPos){
return cellWorldPos.distance(playerPos);
}
/**
@ -337,7 +359,17 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
* @return True if the player changed cell, false otherwise
*/
public boolean updatePlayerPositions(){
Globals.profiler.beginCpuSample("GriddedDataCellManager.updatePlayerPositions");
Globals.profiler.beginCpuSample("GriddedDataCellManager.updatePlayerPositions - Reset chunk distances");
loadedCellsLock.lock();
Globals.profiler.beginCpuSample("GriddedDataCellManager.updatePlayerPositions - Remove from old cells");
for(ServerDataCell cell : this.groundDataCells.values()){
GriddedDataCellTrackingData trackingData = this.cellTrackingMap.get(cell);
trackingData.setClosestPlayer(GriddedDataCellTrackingData.REALLY_LARGE_DISTANCE);
}
loadedCellsLock.unlock();
Globals.profiler.endCpuSample();
Globals.profiler.beginCpuSample("GriddedDataCellManager.updatePlayerPositions - Actually update player positions");
boolean playerChangedChunk = false;
for(Player player : Globals.playerManager.getPlayers()){
Entity playerEntity = player.getPlayerEntity();
@ -355,8 +387,13 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
loadedCellsLock.lock();
Globals.profiler.beginCpuSample("GriddedDataCellManager.updatePlayerPositions - Remove from old cells");
for(ServerDataCell cell : this.groundDataCells.values()){
GriddedDataCellTrackingData trackingData = this.cellTrackingMap.get(cell);
Vector3i cellWorldPos = this.getCellWorldPosition(cell);
if(cell.containsPlayer(player) && !this.shouldContainPlayer(cellWorldPos, newPosition, playerSimulationRadius)){
double distance = this.calcDistance(cellWorldPos, newPosition);
if(distance < trackingData.getClosestPlayer()){
trackingData.setClosestPlayer(distance);
}
if(cell.containsPlayer(player) && !this.shouldContainPlayer(distance, playerSimulationRadius)){
if(cell.getScene().containsEntity(player.getPlayerEntity())){
throw new Error("Trying to remove player from a cell that contains its entity!");
}
@ -369,14 +406,16 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
//Add to cells that are in range
Globals.profiler.beginCpuSample("GriddedDataCellManager.updatePlayerPositions - Create new cells");
Vector3i tempVec = new Vector3i();
for(int x = newPosition.x - playerSimulationRadius + 1; x < newPosition.x + playerSimulationRadius; x++){
for(int y = newPosition.y - playerSimulationRadius + 1; y < newPosition.y + playerSimulationRadius; y++){
for(int z = newPosition.z - playerSimulationRadius + 1; z < newPosition.z + playerSimulationRadius; z++){
if(this.canCreateCell(x,y,z) && this.shouldContainPlayer(new Vector3i(x,y,z), newPosition, playerSimulationRadius)){
Vector3i targetPos = new Vector3i(x,y,z);
if(groundDataCells.get(this.getServerDataCellKey(targetPos)) != null){
tempVec.set(x,y,z);
double distance = this.calcDistance(tempVec, newPosition);
if(this.canCreateCell(x,y,z) && this.shouldContainPlayer(distance, playerSimulationRadius)){
if(groundDataCells.get(this.getServerDataCellKey(tempVec)) != null){
loadedCellsLock.lock();
ServerDataCell cell = groundDataCells.get(this.getServerDataCellKey(targetPos));
ServerDataCell cell = groundDataCells.get(this.getServerDataCellKey(tempVec));
if(!cell.containsPlayer(player)){
cell.addPlayer(player);
}
@ -384,9 +423,9 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
} else {
loadedCellsLock.lock();
//create data cell
this.createServerDataCell(targetPos);
this.createServerDataCell(tempVec);
//add player
groundDataCells.get(this.getServerDataCellKey(targetPos)).addPlayer(player);
groundDataCells.get(this.getServerDataCellKey(tempVec)).addPlayer(player);
loadedCellsLock.unlock();
}
}
@ -484,6 +523,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
groundDataCells.remove(key);
this.posPhysicsMap.remove(key);
this.cellPositionMap.remove(cell);
this.cellTrackingMap.remove(cell);
this.cellPlayerlessFrameMap.remove(cell);
}
Globals.profiler.endCpuSample();
@ -506,12 +546,13 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
}
for(ServerDataCell cell : toCleanQueue){
parent.deregisterCell(cell);
Vector3i worldPos = getCellWorldPosition(cell);
Vector3i worldPos = this.getCellWorldPosition(cell);
Long key = getServerDataCellKey(worldPos);
groundDataCells.remove(key);
this.posPhysicsMap.remove(key);
this.cellPositionMap.remove(cell);
this.cellPlayerlessFrameMap.remove(cell);
this.cellTrackingMap.remove(cell);
//offload all entities in cell to chunk file
serverContentManager.saveContentToDisk(key, cell.getScene().getEntityList());
//clear all entities in cell
@ -644,7 +685,8 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
* @return true if it should be simulated, false otherwise
*/
private boolean shouldSimulate(ServerDataCell cell){
return cell.getPlayers().size() > 0;
GriddedDataCellTrackingData trackingData = this.cellTrackingMap.get(cell);
return cell.getPlayers().size() > 0 && trackingData.getClosestPlayer() < SIMULATION_DISTANCE_CUTOFF;
}
@ -739,24 +781,27 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
private ServerDataCell createServerDataCell(Vector3i worldPos){
Globals.profiler.beginCpuSample("GriddedDataCellManager.createServerDataCell");
ServerDataCell rVal = parent.createNewCell();
Long cellKey = this.getServerDataCellKey(worldPos);
Vector3i localWorldPos = new Vector3i(worldPos);
Long cellKey = this.getServerDataCellKey(localWorldPos);
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));
cellPositionMap.put(rVal,localWorldPos);
GriddedDataCellTrackingData trackingData = new GriddedDataCellTrackingData();
this.cellTrackingMap.put(rVal,trackingData);
loadedCellsLock.unlock();
Long key = this.getServerDataCellKey(worldPos);
Long key = this.getServerDataCellKey(localWorldPos);
//generate content
GriddedDataCellLoaderService.queueLocationBasedOperation(key, () -> {
serverContentManager.generateContentForDataCell(parent, worldPos, rVal, cellKey);
serverContentManager.generateContentForDataCell(parent, localWorldPos, rVal, cellKey);
});
//generates physics for the cell in a dedicated thread then finally registers
loadedCellsLock.lock();
PhysicsDataCell cell = posPhysicsMap.get(key);
GriddedDataCellManager.runPhysicsGenerationThread(worldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.parent);
GriddedDataCellManager.runPhysicsGenerationThread(localWorldPos,key,cell,this.posPhysicsMap,this.groundDataCells,this.parent);
loadedCellsLock.unlock();

View File

@ -0,0 +1,36 @@
package electrosphere.server.datacell.gridded;
/**
* Data associated with a ServerDataCell by the GriddedDataCellManager
*/
public class GriddedDataCellTrackingData {
/**
* A really large distance used to reset the position
*/
public static final double REALLY_LARGE_DISTANCE = 1000;
/**
* The from the cell to the closest player
*/
double closestPlayer;
/**
* Gets the distance from the cell to the closest player
* @return The distance
*/
public double getClosestPlayer() {
return closestPlayer;
}
/**
* Sets the distance to the closest player
* @param closestPlayer The distance to the closest player
*/
public void setClosestPlayer(double closestPlayer) {
this.closestPlayer = closestPlayer;
}
}