Revert "gridded data cell improvements"
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This reverts commit da3ada73d0.
This commit is contained in:
austin 2025-05-25 13:44:53 -04:00
parent 03035aa1fb
commit cf9dceff42
3 changed files with 100 additions and 150 deletions

View File

@ -1988,8 +1988,6 @@ Performance improvements
- Reduce bones on LOD human model - Reduce bones on LOD human model
Increase human move speed Increase human move speed
LOD components re-attach physics LOD components re-attach physics
Memory improvements
- Rely on vector pool more

View File

@ -72,112 +72,112 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
/** /**
* The number of frames without players that must pass before a server data cell is unloaded * The number of frames without players that must pass before a server data cell is unloaded
*/ */
private static final int UNLOAD_FRAME_THRESHOLD = 100; static final int UNLOAD_FRAME_THRESHOLD = 100;
/** /**
* The distance at which simulation is queued * The distance at which simulation is queued
*/ */
private static final double SIMULATION_DISTANCE_CUTOFF = 5; static final double SIMULATION_DISTANCE_CUTOFF = 5;
/** /**
* Big number used when scanning for a data cell to spawn a macro object within * Big number used when scanning for a data cell to spawn a macro object within
*/ */
private static final double MACRO_SCANNING_BIG_NUMBER = 10000; static final double MACRO_SCANNING_BIG_NUMBER = 10000;
/** /**
* Used for generating physics chunks * Used for generating physics chunks
*/ */
private ExecutorService generationService = null; ExecutorService generationService = null;
/** /**
* The service for loading data cells from disk * The service for loading data cells from disk
*/ */
private GriddedDataCellLoaderService loaderService; GriddedDataCellLoaderService loaderService;
/** /**
* Tracks whether this manager has been flagged to unload cells or not * Tracks whether this manager has been flagged to unload cells or not
*/ */
private boolean unloadCells = true; boolean unloadCells = true;
/** /**
* These are going to be the natural ground grid of data cells, but we're going to have more than this * These are going to be the natural ground grid of data cells, but we're going to have more than this
*/ */
private Map<Long,ServerDataCell> groundDataCells = new HashMap<Long,ServerDataCell>(); Map<Long,ServerDataCell> groundDataCells = new HashMap<Long,ServerDataCell>();
/** /**
* Map of server cell to its world position * Map of server cell to its world position
*/ */
private Map<ServerDataCell,Vector3i> cellPositionMap = new HashMap<ServerDataCell,Vector3i>(); Map<ServerDataCell,Vector3i> cellPositionMap = new HashMap<ServerDataCell,Vector3i>();
/** /**
* Map of server data cell to the number of frames said cell has had no players * Map of server data cell to the number of frames said cell has had no players
*/ */
private Map<ServerDataCell,Integer> cellPlayerlessFrameMap = new HashMap<ServerDataCell,Integer>(); Map<ServerDataCell,Integer> cellPlayerlessFrameMap = new HashMap<ServerDataCell,Integer>();
/** /**
* A map of ServerDataCell->GriddedDataCellTrackingData * A map of ServerDataCell->GriddedDataCellTrackingData
*/ */
private Map<ServerDataCell,GriddedDataCellTrackingData> cellTrackingMap = new HashMap<ServerDataCell,GriddedDataCellTrackingData>(); Map<ServerDataCell,GriddedDataCellTrackingData> cellTrackingMap = new HashMap<ServerDataCell,GriddedDataCellTrackingData>();
/** /**
* Loaded cells * Loaded cells
*/ */
private ReentrantLock loadedCellsLock = new ReentrantLock(); ReentrantLock loadedCellsLock = new ReentrantLock();
/** /**
* Parent realm * Parent realm
*/ */
private Realm parent; Realm parent;
/** /**
* The world data of the parent * The world data of the parent
*/ */
private ServerWorldData serverWorldData; ServerWorldData serverWorldData;
/** /**
* Manager for terrain for this particular cell manager * Manager for terrain for this particular cell manager
*/ */
private ServerTerrainManager serverTerrainManager; ServerTerrainManager serverTerrainManager;
/** /**
* Manager for fluids for this particular cell manager * Manager for fluids for this particular cell manager
*/ */
private ServerFluidManager serverFluidManager; ServerFluidManager serverFluidManager;
/** /**
* Lock for terrain editing * Lock for terrain editing
*/ */
private Semaphore terrainEditLock = new Semaphore(1); Semaphore terrainEditLock = new Semaphore(1);
/** /**
* Manager for getting entities to fill in a cell * Manager for getting entities to fill in a cell
*/ */
private ServerContentManager serverContentManager; ServerContentManager serverContentManager;
/** /**
* Used for cleaning server data cells no longer in use from the realm * Used for cleaning server data cells no longer in use from the realm
*/ */
private Set<ServerDataCell> toCleanQueue = new HashSet<ServerDataCell>(); Set<ServerDataCell> toCleanQueue = new HashSet<ServerDataCell>();
/** /**
* Map of world position key -> physics cell * Map of world position key -> physics cell
*/ */
private Map<Long,PhysicsDataCell> posPhysicsMap = new HashMap<Long,PhysicsDataCell>(); Map<Long,PhysicsDataCell> posPhysicsMap = new HashMap<Long,PhysicsDataCell>();
/** /**
* Number of data cells cleaned up in the most recent frame * Number of data cells cleaned up in the most recent frame
*/ */
private int numCleaned = 0; int numCleaned = 0;
/** /**
* Queue of cells that need to have their physics regenerated (ie on block edits) * Queue of cells that need to have their physics regenerated (ie on block edits)
*/ */
private Map<Long,Vector3i> physicsQueue = new HashMap<Long,Vector3i>(); Map<Long,Vector3i> physicsQueue = new HashMap<Long,Vector3i>();
/** /**
* The pathfinder for the manager * The pathfinder for the manager
*/ */
private VoxelPathfinder pathfinder; VoxelPathfinder pathfinder;
/** /**
* Caches lookups for nearby entities between simulate() calls * Caches lookups for nearby entities between simulate() calls
@ -359,7 +359,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
loadedCellsLock.lock(); loadedCellsLock.lock();
if(posPhysicsMap.containsKey(key)){ if(posPhysicsMap.containsKey(key)){
PhysicsDataCell cell = posPhysicsMap.get(key); PhysicsDataCell cell = posPhysicsMap.get(key);
cell.destroyEntities(); cell.retireCell();
} }
loadedCellsLock.unlock(); loadedCellsLock.unlock();
//get data to generate with //get data to generate with
@ -384,7 +384,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
//the server will not be able to synchronize it properly. //the server will not be able to synchronize it properly.
ServerEntityUtils.initiallyPositionEntity(parent,blockEntity,realPos); ServerEntityUtils.initiallyPositionEntity(parent,blockEntity,realPos);
ServerEntityUtils.initiallyPositionEntity(parent,terrainEntity,realPos); ServerEntityUtils.initiallyPositionEntity(parent,terrainEntity,realPos);
PhysicsDataCell cell = PhysicsDataCell.createPhysicsCell(terrainEntity, blockEntity); PhysicsDataCell cell = PhysicsDataCell.createPhysicsCell(worldPos, terrainEntity, blockEntity);
cell.setTerrainChunk(terrainChunk); cell.setTerrainChunk(terrainChunk);
cell.setBlockChunk(blockChunkData); cell.setBlockChunk(blockChunkData);
cell.generatePhysics(); cell.generatePhysics();
@ -545,8 +545,39 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
continue; continue;
} }
this.unloadCell(cell);
Vector3i worldPos = this.getCellWorldPosition(cell);
Long key = this.getServerDataCellKey(worldPos);
//entities are serialized 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
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Serialize entities");
ContentSerialization serializedEntities = ContentSerialization.constructContentSerialization(cell.getScene().getEntityList());
Globals.profiler.endCpuSample();
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Destroy entities");
for(Entity entity : cell.getScene().getEntityList()){
ServerEntityUtils.destroyEntity(entity);
}
Globals.profiler.endCpuSample();
//save terrain to disk
//terrain is saved before tracking is removed. This makes sure that any side effects from calling savePositionToDisk (ie if it looks up the chunk that we're deleting)
//don't trigger the chunk to be re-created
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Store data");
this.loaderService.queueLocationBasedOperation(key, () -> {
serverContentManager.saveSerializationToDisk(key, serializedEntities);
serverTerrainManager.savePositionToDisk(worldPos);
});
Globals.profiler.endCpuSample();
//deregister from all tracking structures
parent.deregisterCell(cell);
groundDataCells.remove(key);
this.posPhysicsMap.remove(key);
this.cellPositionMap.remove(cell);
this.cellTrackingMap.remove(cell);
this.cellPlayerlessFrameMap.remove(cell);
} }
Globals.profiler.endCpuSample(); Globals.profiler.endCpuSample();
loadedCellsLock.unlock(); loadedCellsLock.unlock();
@ -567,55 +598,26 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
toCleanQueue.add(cell); toCleanQueue.add(cell);
} }
for(ServerDataCell cell : toCleanQueue){ for(ServerDataCell cell : toCleanQueue){
this.unloadCell(cell); parent.deregisterCell(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
for(Entity entity : cell.getScene().getEntityList()){
ServerEntityUtils.destroyEntity(entity);
}
} }
loadedCellsLock.unlock(); loadedCellsLock.unlock();
this.serverTerrainManager.evictAll(); this.serverTerrainManager.evictAll();
toCleanQueue.clear(); toCleanQueue.clear();
} }
/**
* Unloads a server data cell
* @param cell The cell
*/
public void unloadCell(ServerDataCell cell){
Vector3i worldPos = this.getCellWorldPosition(cell);
Long key = this.getServerDataCellKey(worldPos);
//entities are serialized 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
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Serialize entities");
ContentSerialization serializedEntities = ContentSerialization.constructContentSerialization(cell.getScene().getEntityList());
Globals.profiler.endCpuSample();
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Destroy entities");
for(Entity entity : cell.getScene().getEntityList()){
ServerEntityUtils.destroyEntity(entity);
}
Globals.profiler.endCpuSample();
//save terrain to disk
//terrain is saved before tracking is removed. This makes sure that any side effects from calling savePositionToDisk (ie if it looks up the chunk that we're deleting)
//don't trigger the chunk to be re-created
Globals.profiler.beginCpuSample("GriddedDataCellManager.unloadPlayerlessChunks - Store data");
this.loaderService.queueLocationBasedOperation(key, () -> {
serverContentManager.saveSerializationToDisk(key, serializedEntities);
serverTerrainManager.savePositionToDisk(worldPos);
});
Globals.profiler.endCpuSample();
//deregister from all tracking structures
this.parent.deregisterCell(cell);
this.groundDataCells.remove(key);
PhysicsDataCell releasedCell = this.posPhysicsMap.remove(key);
if(releasedCell != null){
releasedCell.destroyEntities();
}
this.cellPositionMap.remove(cell);
this.cellTrackingMap.remove(cell);
this.cellPlayerlessFrameMap.remove(cell);
}
/** /**
* Get data cell at a given real point in this realm * Get data cell at a given real point in this realm
* @param point The real point * @param point The real point
@ -817,7 +819,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
ServerEntityUtils.initiallyPositionEntity(realm,blockEntity,realPos); ServerEntityUtils.initiallyPositionEntity(realm,blockEntity,realPos);
ServerEntityUtils.initiallyPositionEntity(realm,terrainEntity,realPos); ServerEntityUtils.initiallyPositionEntity(realm,terrainEntity,realPos);
PhysicsDataCell targetCell = PhysicsDataCell.createPhysicsCell(terrainEntity, blockEntity); PhysicsDataCell targetCell = PhysicsDataCell.createPhysicsCell(worldPos, terrainEntity, blockEntity);
if(cell == null){ if(cell == null){
posPhysicsMap.put(key, targetCell); posPhysicsMap.put(key, targetCell);
} else { } else {
@ -845,7 +847,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
//create physics entities //create physics entities
if(cell != null){ if(cell != null){
cell.destroyEntities(); cell.retireCell();
cell.generatePhysics(); cell.generatePhysics();
} else { } else {
targetCell.generatePhysics(); targetCell.generatePhysics();
@ -880,9 +882,6 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
Long cellKey = this.getServerDataCellKey(localWorldPos); Long cellKey = this.getServerDataCellKey(localWorldPos);
loadedCellsLock.lock(); loadedCellsLock.lock();
if(groundDataCells.containsKey(cellKey)){
throw new Error("Creating server data cell at position that already has a cell! " + localWorldPos);
}
groundDataCells.put(cellKey,rVal); groundDataCells.put(cellKey,rVal);
cellPlayerlessFrameMap.put(rVal,0); cellPlayerlessFrameMap.put(rVal,0);
LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + cellKey); LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + cellKey);
@ -1155,21 +1154,6 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
return cellPlayerlessFrameMap; return cellPlayerlessFrameMap;
} }
/**
* Gets the tracking data for a cell
* @param cell The cell
* @return The tracking data as a string
*/
public String getCellData(ServerDataCell cell){
String message = "Failed to find position of cell!\n" +
"groundDataCells: " + this.groundDataCells.values().contains(cell) + "\n" +
"cellPositionMap: " + this.cellPositionMap.keySet().contains(cell) + "\n" +
"cellPlayerlessFrameMap: " + this.cellPositionMap.keySet().contains(cell) + "\n" +
"cellTrackingMap: " + this.cellTrackingMap.keySet().contains(cell) + "\n" +
"";
return message;
}
@Override @Override
public List<Vector3d> findPath(Vector3d start, Vector3d end){ public List<Vector3d> findPath(Vector3d start, Vector3d end){
Vector3i startChunkPos = ServerWorldData.convertRealToChunkSpace(start); Vector3i startChunkPos = ServerWorldData.convertRealToChunkSpace(start);

View File

@ -3,6 +3,7 @@ package electrosphere.server.datacell.physics;
import electrosphere.client.block.BlockChunkData; import electrosphere.client.block.BlockChunkData;
import electrosphere.client.terrain.cache.ChunkData; import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.client.terrain.data.TerrainChunkData; import electrosphere.client.terrain.data.TerrainChunkData;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.ServerEntityUtils;
@ -10,54 +11,39 @@ import electrosphere.entity.types.terrain.BlockChunkEntity;
import electrosphere.entity.types.terrain.TerrainChunk; import electrosphere.entity.types.terrain.TerrainChunk;
import electrosphere.renderer.meshgen.BlockMeshgen; import electrosphere.renderer.meshgen.BlockMeshgen;
import electrosphere.renderer.meshgen.BlockMeshgen.BlockMeshData; import electrosphere.renderer.meshgen.BlockMeshgen.BlockMeshData;
import electrosphere.server.datacell.Realm;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk; import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
import org.joml.Vector3i; import org.joml.Vector3i;
import org.ode4j.ode.DBody;
/** /**
* An entity which contains physics for terrain for a given chunk on the server * An entity which contains physics for terrain for a given chunk on the server
*/ */
public class PhysicsDataCell { public class PhysicsDataCell {
Vector3i worldPos;
/** Entity physicsEntity;
* The terrain physics entity Entity blockPhysicsEntity;
*/
private Entity physicsEntity;
/** ServerTerrainChunk terrainChunk;
* The block physics entity BlockChunkData blockChunk;
*/
private Entity blockPhysicsEntity; DBody physicsObject;
/** float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
* The terrain chunk data int[][][] types = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
*/
private ServerTerrainChunk terrainChunk;
/**
* The block chunk data
*/
private BlockChunkData blockChunk;
/**
* The weight data
*/
private float[][][] weights = new float[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
/**
* The type data
*/
private int[][][] types = new int[ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE][ServerTerrainChunk.CHUNK_DATA_GENERATOR_SIZE];
/** /**
* The terrain vertex data * The terrain vertex data
*/ */
private TerrainChunkData terrainChunkData; TerrainChunkData terrainChunkData;
/** /**
* The block vertex data * The block vertex data
*/ */
private BlockMeshData blockData; BlockMeshData blockData;
/** /**
* Creates a physics cell * Creates a physics cell
@ -66,6 +52,7 @@ public class PhysicsDataCell {
* @return The cell * @return The cell
*/ */
public static PhysicsDataCell createPhysicsCell( public static PhysicsDataCell createPhysicsCell(
Vector3i worldPos,
Entity physicsEntity, Entity physicsEntity,
Entity blockPhysicsEntity Entity blockPhysicsEntity
@ -73,47 +60,19 @@ public class PhysicsDataCell {
PhysicsDataCell rVal = new PhysicsDataCell(); PhysicsDataCell rVal = new PhysicsDataCell();
rVal.physicsEntity = physicsEntity; rVal.physicsEntity = physicsEntity;
rVal.blockPhysicsEntity = blockPhysicsEntity; rVal.blockPhysicsEntity = blockPhysicsEntity;
rVal.worldPos = worldPos;
return rVal; return rVal;
} }
/** /**
* Retires a physics data cell * Retires a physics data cell
*/ */
public void destroyEntities(){ public void retireCell(){
ServerEntityUtils.destroyEntity(physicsEntity); ServerEntityUtils.destroyEntity(physicsEntity);
this.physicsEntity = null; this.physicsEntity = null;
ServerEntityUtils.destroyEntity(blockPhysicsEntity); ServerEntityUtils.destroyEntity(blockPhysicsEntity);
this.blockPhysicsEntity = null; this.blockPhysicsEntity = null;
} }
/**
* Frees the data in this cell
*/
public void free(){
this.destroyEntities();
}
/**
* Resets the state of the physics data cell
*/
public void reset(
Vector3i worldPos,
Entity physicsEntity,
Entity blockPhysicsEntity
){
if(this.physicsEntity != null){
ServerEntityUtils.destroyEntity(this.physicsEntity);
}
if(this.blockPhysicsEntity != null){
ServerEntityUtils.destroyEntity(this.blockPhysicsEntity);
}
this.physicsEntity = physicsEntity;
this.blockPhysicsEntity = blockPhysicsEntity;
this.terrainChunk = null;
this.blockChunk = null;
this.terrainChunkData = null;
this.blockData = null;
}
/** /**
* Generates the physics entity for this chunk * Generates the physics entity for this chunk
@ -146,6 +105,15 @@ public class PhysicsDataCell {
localBlockPhysicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); localBlockPhysicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true);
localBlockPhysicsEntity.putData(EntityDataStrings.BLOCK_ENTITY, true); localBlockPhysicsEntity.putData(EntityDataStrings.BLOCK_ENTITY, true);
} }
/**
* Destroys the physics for this data cell
*/
public void destroyPhysics(){
Realm realm = Globals.serverState.realmManager.getEntityRealm(physicsEntity);
realm.getCollisionEngine().destroyPhysics(physicsEntity);
realm.getCollisionEngine().destroyPhysics(blockPhysicsEntity);
}
/** /**
* Fills in the internal arrays of data for generate terrain models * Fills in the internal arrays of data for generate terrain models