grid manager entity and player tracking overhaul
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2024-11-08 12:11:40 -05:00
parent e12dd55703
commit 795fbb6a1c
24 changed files with 400 additions and 220 deletions

View File

@ -1,6 +1,6 @@
{ {
"gameplayGenerateWorld" : false, "gameplayGenerateWorld" : false,
"gameplayPhysicsCellRadius" : 2, "gameplayPhysicsCellRadius" : 3,
"displayWidth" : 1920, "displayWidth" : 1920,
"displayHeight" : 1080, "displayHeight" : 1080,

View File

@ -9,3 +9,8 @@ sines pulling from sines
noise functions pulling from sines noise functions pulling from sines
applying 2d values to the surface (top) of a 3d noise map applying 2d values to the surface (top) of a 3d noise map
subtracting true 3d noise from a 2d heightmap to account for cave entrances subtracting true 3d noise from a 2d heightmap to account for cave entrances
spatially partitioning 3d shapes using the same trick as the voronoi noise but in 3d
IE, have a torus defined in 3d that is bounded in cells

View File

@ -0,0 +1,51 @@
package electrosphere.client.ui.menu.debug;
import electrosphere.engine.Globals;
import electrosphere.renderer.ui.imgui.ImGuiWindow;
import electrosphere.renderer.ui.imgui.ImGuiWindow.ImGuiWindowCallback;
import electrosphere.server.datacell.GriddedDataCellManager;
import electrosphere.server.datacell.Realm;
import imgui.ImGui;
/**
*
*/
public class ImGuiGriddedManager {
//window for viewing information about the ai state
protected static ImGuiWindow griddedManagerWindow;
/**
* Creates the windows in this file
*/
protected static void createGriddedManagerWindows(){
createGriddedManagerWindow();
}
/**
* Client scene entity view
*/
protected static void createGriddedManagerWindow(){
griddedManagerWindow = new ImGuiWindow("Gridded Manager");
griddedManagerWindow.setCallback(new ImGuiWindowCallback() {
@Override
public void exec() {
GriddedDataCellManager manager = null;
if(Globals.realmManager != null && Globals.realmManager.first() != null){
Realm realm = Globals.realmManager.first();
if(realm.getDataCellManager() instanceof GriddedDataCellManager){
manager = (GriddedDataCellManager)realm.getDataCellManager();
}
}
if(manager != null && manager.getLoadedCells() != null){
ImGui.text("Loaded Cells: " + manager.getLoadedCells().size());
}
}
});
griddedManagerWindow.setOpen(false);
Globals.renderingEngine.getImGuiPipeline().addImGuiWindow(griddedManagerWindow);
}
}

View File

@ -52,6 +52,7 @@ public class ImGuiWindowMacros {
ImGuiRenderer.createRendererWindows(); ImGuiRenderer.createRendererWindows();
ImGuiTestGen.createTestGenWindows(); ImGuiTestGen.createTestGenWindows();
ImGuiChunkMonitor.createChunkMonitorWindows(); ImGuiChunkMonitor.createChunkMonitorWindows();
ImGuiGriddedManager.createGriddedManagerWindows();
} }
/** /**
@ -188,6 +189,10 @@ public class ImGuiWindowMacros {
if(ImGui.button("Chunk Monitor")){ if(ImGui.button("Chunk Monitor")){
ImGuiChunkMonitor.chunkMonitorWindow.setOpen(true); ImGuiChunkMonitor.chunkMonitorWindow.setOpen(true);
} }
//gridded data cell monitor
if(ImGui.button("Gridded Data Cell Monitor")){
ImGuiGriddedManager.griddedManagerWindow.setOpen(true);
}
//close button //close button
if(ImGui.button("Close")){ if(ImGui.button("Close")){
mainDebugWindow.setOpen(false); mainDebugWindow.setOpen(false);

View File

@ -50,10 +50,15 @@ public class EntityCreationUtils {
throw new IllegalStateException("Failed to create a server data cell"); throw new IllegalStateException("Failed to create a server data cell");
} }
//register to entity data cell mapper //register to entity data cell mapper
realm.getEntityDataCellMapper().registerEntity(rVal, cell); Globals.entityDataCellMapper.registerEntity(rVal, cell);
//enable behavior tree tracking //enable behavior tree tracking
ServerBehaviorTreeUtils.registerEntity(rVal); ServerBehaviorTreeUtils.registerEntity(rVal);
if(Globals.entityDataCellMapper.getEntityDataCell(rVal) == null){
Globals.entityDataCellMapper.registerEntity(rVal, cell);
throw new Error("Failed to map entity to cell!");
}
return rVal; return rVal;
} }

View File

@ -43,11 +43,11 @@ public class EntityUtils {
Realm realm = Globals.realmManager.getEntityRealm(e); Realm realm = Globals.realmManager.getEntityRealm(e);
if(realm != null){ if(realm != null){
//get data cell //get data cell
ServerDataCell dataCell = realm.getEntityDataCellMapper().getEntityDataCell(e); ServerDataCell dataCell = Globals.entityDataCellMapper.getEntityDataCell(e);
if(dataCell != null){ if(dataCell != null){
dataCell.getScene().deregisterEntity(e); dataCell.getScene().deregisterEntity(e);
} }
realm.getEntityDataCellMapper().ejectEntity(e); Globals.entityDataCellMapper.ejectEntity(e);
} }
Globals.realmManager.removeEntity(e); Globals.realmManager.removeEntity(e);
} }

View File

@ -33,6 +33,9 @@ public class ServerEntityUtils {
* @param position * @param position
*/ */
public static void initiallyPositionEntity(Realm realm, Entity entity, Vector3d position){ public static void initiallyPositionEntity(Realm realm, Entity entity, Vector3d position){
if(position == null){
throw new Error("Trying to set server entity position to null!");
}
//reposition entity, if the position isn't correct then it will spawn at 0,0,0 when the synchronization part is called //reposition entity, if the position isn't correct then it will spawn at 0,0,0 when the synchronization part is called
CollisionObjUtils.serverPositionCharacter(entity, position); CollisionObjUtils.serverPositionCharacter(entity, position);
//get current server data cell //get current server data cell
@ -43,6 +46,9 @@ public class ServerEntityUtils {
} else { } else {
//if it doesn't already exist, try creating it and if successfull move creature //if it doesn't already exist, try creating it and if successfull move creature
cell = realm.getDataCellManager().tryCreateCellAtPoint(position); cell = realm.getDataCellManager().tryCreateCellAtPoint(position);
if(cell == null){
throw new Error("Trying to initially position entity to position that cannot generate a data cell! " + position);
}
//initialize server datacell tracking of this entity //initialize server datacell tracking of this entity
realm.initializeServerSideEntity(entity, cell); realm.initializeServerSideEntity(entity, cell);
} }
@ -54,25 +60,34 @@ public class ServerEntityUtils {
* @param position * @param position
*/ */
public static void repositionEntity(Entity entity, Vector3d position){ public static void repositionEntity(Entity entity, Vector3d position){
if(position == null){
throw new Error("Trying to set server entity position to null!");
}
Realm realm = Globals.realmManager.getEntityRealm(entity); Realm realm = Globals.realmManager.getEntityRealm(entity);
//if server, get current server data cell //if server, get current server data cell
ServerDataCell oldDataCell = realm.getDataCellManager().getDataCellAtPoint(EntityUtils.getPosition(entity)); ServerDataCell oldDataCell = Globals.entityDataCellMapper.getEntityDataCell(entity);
ServerDataCell newDataCell = realm.getDataCellManager().getDataCellAtPoint(position); ServerDataCell newDataCell = realm.getDataCellManager().getDataCellAtPoint(position);
if(oldDataCell == null){ if(oldDataCell == null){
LoggerInterface.loggerEngine.WARNING("Trying to reposition entity on server when it's former position is null!"); LoggerInterface.loggerEngine.WARNING(
"Trying to reposition entity on server when it's former cell is null!\n" +
"Entity original position: " + EntityUtils.getPosition(entity) + "\n"
);
} }
if(oldDataCell != newDataCell){ if(oldDataCell != newDataCell){
if(newDataCell != null){ if(newDataCell == null){
ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell); newDataCell = realm.getDataCellManager().tryCreateCellAtPoint(position);
ServerBehaviorTreeUtils.updateCell(entity, oldDataCell); if(newDataCell == null){
} else { LoggerInterface.loggerEngine.WARNING(
//if it doesn't already exist, try creating it and if successfull move creature "Trying to reposition entity on server when it's new cell is null!\n" +
newDataCell = realm.getDataCellManager().tryCreateCellAtPoint(EntityUtils.getPosition(entity)); "Entity new position: " + position + "\n"
if(newDataCell != null){ );
ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell);
ServerBehaviorTreeUtils.updateCell(entity, oldDataCell);
} }
} }
ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell);
ServerBehaviorTreeUtils.updateCell(entity, oldDataCell);
if(oldDataCell.getScene().containsEntity(entity)){
throw new Error("Entity not removed from scene!");
}
} }
//reposition entity //reposition entity
CollisionObjUtils.serverPositionCharacter(entity, position); CollisionObjUtils.serverPositionCharacter(entity, position);

View File

@ -7,6 +7,7 @@ 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 java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -19,13 +20,24 @@ import java.util.concurrent.CopyOnWriteArraySet;
*/ */
public class Scene { public class Scene {
/**
* The map of id -> entity
*/
Map<Integer,Entity> entityIdMap; Map<Integer,Entity> entityIdMap;
Map<String,Set<Entity>> tagEntityMap;
List<Entity> entityList = new CopyOnWriteArrayList<Entity>();
/**
* The map of tag -> set of entities corresponding to that tag
*/
Map<String,Set<Entity>> tagEntityMap;
/**
* The list of behavior trees
*/
List<BehaviorTree> behaviorTreeList; List<BehaviorTree> behaviorTreeList;
/**
* Constructor
*/
public Scene(){ public Scene(){
entityIdMap = new ConcurrentHashMap<Integer,Entity>(); entityIdMap = new ConcurrentHashMap<Integer,Entity>();
tagEntityMap = new ConcurrentHashMap<String,Set<Entity>>(); tagEntityMap = new ConcurrentHashMap<String,Set<Entity>>();
@ -53,9 +65,6 @@ 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){
if(!entityIdMap.containsKey(e.getId())){
entityList.add(e);
}
entityIdMap.put(e.getId(), e); entityIdMap.put(e.getId(), e);
} }
@ -101,7 +110,6 @@ public class Scene {
tagEntityMap.get(key).remove(e); tagEntityMap.get(key).remove(e);
} }
entityIdMap.remove(e.getId()); entityIdMap.remove(e.getId());
entityList.remove(e);
} }
/** /**
@ -112,10 +120,10 @@ public class Scene {
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){
recursiveDeregister(currentChild); this.recursiveDeregister(currentChild);
} }
} }
deregisterEntity(target); this.deregisterEntity(target);
} }
/** /**
@ -166,11 +174,11 @@ public class Scene {
} }
/** /**
* Gets the list of all entities in the scene * Gets the collection of all entities in the scene
* @return The list of all entities in the scene * @return The collection of all entities in the scene
*/ */
public List<Entity> getEntityList(){ public Collection<Entity> getEntityList(){
return entityList; return this.entityIdMap.values();
} }
/** /**
@ -178,7 +186,7 @@ public class Scene {
*/ */
public void describeScene(){ public void describeScene(){
LoggerInterface.loggerEngine.WARNING("Entities present in scene:"); LoggerInterface.loggerEngine.WARNING("Entities present in scene:");
for(Entity entity : this.entityList){ for(Entity entity : this.entityIdMap.values()){
LoggerInterface.loggerEngine.WARNING(entity.getId() + ""); LoggerInterface.loggerEngine.WARNING(entity.getId() + "");
} }
} }

View File

@ -166,6 +166,9 @@ public class InventoryUtils {
* @return The in-inventory item * @return The in-inventory item
*/ */
public static Entity serverAttemptStoreItemTransform(Entity creature, Entity item){ public static Entity serverAttemptStoreItemTransform(Entity creature, Entity item){
if(item == null){
throw new Error("Null item provided! " + item);
}
boolean creatureIsCreature = CreatureUtils.isCreature(creature); boolean creatureIsCreature = CreatureUtils.isCreature(creature);
boolean itemIsItem = ItemUtils.isItem(item); boolean itemIsItem = ItemUtils.isItem(item);
boolean hasInventory = hasNaturalInventory(creature); boolean hasInventory = hasNaturalInventory(creature);
@ -360,7 +363,7 @@ public class InventoryUtils {
Realm realm = Globals.realmManager.getEntityRealm(realWorldItem); Realm realm = Globals.realmManager.getEntityRealm(realWorldItem);
if(realm != null){ if(realm != null){
//get closest chunk //get closest chunk
ServerDataCell dataCell = realm.getEntityDataCellMapper().getEntityDataCell(realWorldItem); ServerDataCell dataCell = Globals.entityDataCellMapper.getEntityDataCell(realWorldItem);
//broadcast destroy item //broadcast destroy item
NetworkMessage unequipMessage = InventoryMessage.constructserverCommandUnequipItemMessage(creature.getId(), InventoryProtocol.INVENTORY_TYPE_EQUIP, inventorySlot); NetworkMessage unequipMessage = InventoryMessage.constructserverCommandUnequipItemMessage(creature.getId(), InventoryProtocol.INVENTORY_TYPE_EQUIP, inventorySlot);
dataCell.broadcastNetworkMessage(unequipMessage); dataCell.broadcastNetworkMessage(unequipMessage);

View File

@ -240,56 +240,6 @@ public class ClientEditorMovementTree implements BehaviorTree {
Quaterniond movementQuaternion = new Quaterniond().rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize(); Quaterniond movementQuaternion = new Quaterniond().rotationTo(SpatialMathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize();
Quaterniond rotation = EntityUtils.getRotation(parent); Quaterniond rotation = EntityUtils.getRotation(parent);
//parse attached network messages
for(EntityMessage message : networkMessageQueue){
networkMessageQueue.remove(message);
long updateTime = message.gettime();
// System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ());
switch(message.getMessageSubtype()){
case MOVEUPDATE:
if(updateTime >= lastUpdateTime){
lastUpdateTime = updateTime;
switch(message.gettreeState()){
case 0:
state = MovementTreeState.STARTUP;
// System.out.println("Set state STARTUP");
GravityUtils.clientAttemptActivateGravity(parent);
break;
case 1:
state = MovementTreeState.MOVE;
// System.out.println("Set state MOVE");
GravityUtils.clientAttemptActivateGravity(parent);
break;
case 2:
state = MovementTreeState.SLOWDOWN;
// System.out.println("Set state SLOWDOWN");
GravityUtils.clientAttemptActivateGravity(parent);
break;
case 3:
state = MovementTreeState.IDLE;
// System.out.println("Set state IDLE");
break;
}
//this should only fire on the client, we don't want the server snap updating due to client position reporting
lastServerPosition = new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ());
if(position.distance(lastServerPosition) > STATE_DIFFERENCE_HARD_UPDATE_THRESHOLD){
EntityUtils.getPosition(parent).set(lastServerPosition);
} else if(position.distance(lastServerPosition) > STATE_DIFFERENCE_SOFT_UPDATE_THRESHOLD){
EntityUtils.getPosition(parent).lerp(lastServerPosition,SOFT_UPDATE_MULTIPLIER);
}
//we want to always update the server facing vector with where the client says they're facing
EntityUtils.getRotation(parent).set(message.getrotationX(),message.getrotationY(),message.getrotationZ(),message.getrotationW());
CollisionObjUtils.clientPositionCharacter(parent, position, rotation);
// CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ()));
break;
}
break;
default:
break;
}
}
// System.out.println(movementVector + " " + velocity * Main.deltaTime);
//state machine //state machine
switch(state){ switch(state){

View File

@ -65,6 +65,11 @@ public class CollisionObjUtils {
entity.putData(EntityDataStrings.PHYSICS_MASS, mass); entity.putData(EntityDataStrings.PHYSICS_MASS, mass);
} }
/**
* Repositions an entity on the server
* @param e The entity
* @param position The server
*/
public static void serverPositionCharacter(Entity e, Vector3d position){ public static void serverPositionCharacter(Entity e, Vector3d position){
EntityUtils.getPosition(e).set(position); EntityUtils.getPosition(e).set(position);
Quaterniond rotation = EntityUtils.getRotation(e); Quaterniond rotation = EntityUtils.getRotation(e);
@ -75,6 +80,12 @@ public class CollisionObjUtils {
} }
} }
/**
* Positions an entity on the client
* @param e The entity
* @param position The position
* @param rotation The rotation
*/
public static void clientPositionCharacter(Entity e, Vector3d position, Quaterniond rotation){ public static void clientPositionCharacter(Entity e, Vector3d position, Quaterniond rotation){
EntityUtils.getPosition(e).set(position); EntityUtils.getPosition(e).set(position);
DBody body = PhysicsEntityUtils.getDBody(e); DBody body = PhysicsEntityUtils.getDBody(e);

View File

@ -689,6 +689,10 @@ public class CommonEntityUtils {
ServerEntityTagUtils.attachTagToEntity(entity, EntityTags.LIFE_STATE); ServerEntityTagUtils.attachTagToEntity(entity, EntityTags.LIFE_STATE);
} }
if(Globals.entityDataCellMapper.getEntityDataCell(entity) == null){
throw new Error("Failed to map entity to cell!");
}
return entity; return entity;
} }

View File

@ -402,6 +402,13 @@ public class CreatureUtils {
if(CreatureUtils.hasControllerPlayerId(creature)){ if(CreatureUtils.hasControllerPlayerId(creature)){
LoggerInterface.loggerNetworking.INFO("Sending controller packets"); LoggerInterface.loggerNetworking.INFO("Sending controller packets");
player.addMessage(NetUtils.createSetCreatureControllerIdEntityMessage(creature)); player.addMessage(NetUtils.createSetCreatureControllerIdEntityMessage(creature));
Player entityOwner = Globals.playerManager.getPlayerFromId(CreatureUtils.getControllerPlayerId(creature));
if(entityOwner == player){
player.setHasSentPlayerEntity(true);
}
if(Globals.playerEntity != null && player.getId() == Globals.clientPlayer.getId() && player.getPlayerEntity() == creature){
throw new Error("Re-sending player entity to player!");
}
} }
} }

View File

@ -53,6 +53,11 @@ public class Player {
* The player's primary entity * The player's primary entity
*/ */
Entity playerEntity; Entity playerEntity;
/**
* Tracks whether the player's entity has been sent or not
*/
boolean hasSentPlayerEntity = false;
/** /**
* Constructor * Constructor
@ -151,6 +156,24 @@ public class Player {
idIncrementerLock.release(); idIncrementerLock.release();
return rVal; return rVal;
} }
/**
* Gets whether the player has been sent their entity or not
* @return true if has been sent, false otherwise
*/
public boolean hasSentPlayerEntity() {
return hasSentPlayerEntity;
}
/**
* Sets whether the player has been sent their entity or not
* @param hasSentPlayerEntity true if has been sent, false otherwise
*/
public void setHasSentPlayerEntity(boolean hasSentPlayerEntity) {
this.hasSentPlayerEntity = hasSentPlayerEntity;
}
} }

View File

@ -64,14 +64,16 @@ public class ServerContentGenerator {
double scale = foliageDescription.getScale(); double scale = foliageDescription.getScale();
double regularity = foliageDescription.getRegularity(); double regularity = foliageDescription.getRegularity();
double threshold = foliageDescription.getThreshold(); double threshold = foliageDescription.getThreshold();
if(NoiseUtils.relaxedPointGen(x * scale, z * scale, regularity, threshold) > 0){ double realX = realm.getServerWorldData().convertVoxelToRealSpace(x, worldPos.x);
double realZ = realm.getServerWorldData().convertVoxelToRealSpace(z, worldPos.z);
if(NoiseUtils.relaxedPointGen(realX * scale, realZ * scale, regularity, threshold) > 0){
String type = foliageDescription.getEntityIDs().get(random.nextInt(0,foliageDescription.getEntityIDs().size())); String type = foliageDescription.getEntityIDs().get(random.nextInt(0,foliageDescription.getEntityIDs().size()));
FoliageUtils.serverSpawnTreeFoliage( FoliageUtils.serverSpawnTreeFoliage(
realm, realm,
new Vector3d( new Vector3d(
realm.getServerWorldData().convertVoxelToRealSpace(x, worldPos.x), realX,
height, height,
realm.getServerWorldData().convertVoxelToRealSpace(z, worldPos.z) realZ
), ),
type, type,
random.nextLong() random.nextLong()

View File

@ -1,5 +1,6 @@
package electrosphere.server.content; package electrosphere.server.content;
import java.util.Collection;
import java.util.List; import java.util.List;
import org.joml.Vector3i; import org.joml.Vector3i;
@ -73,9 +74,9 @@ public class ServerContentManager {
/** /**
* Saves entity content to disk * Saves entity content to disk
* @param locationKey the location key to save under * @param locationKey the location key to save under
* @param entities the list of entities to save * @param entities the collection of entities to save
*/ */
public void saveContentToDisk(Long locationKey, List<Entity> entities){ public void saveContentToDisk(Long locationKey, Collection<Entity> entities){
ContentSerialization serialization = ContentSerialization.constructContentSerialization(entities); ContentSerialization serialization = ContentSerialization.constructContentSerialization(entities);
String dirPath = SaveUtils.deriveSaveDirectoryPath(Globals.currentSave.getName()); String dirPath = SaveUtils.deriveSaveDirectoryPath(Globals.currentSave.getName());
String fullPath = dirPath + "/content/" + locationKey + ".dat"; String fullPath = dirPath + "/content/" + locationKey + ".dat";

View File

@ -1,5 +1,6 @@
package electrosphere.server.content.serialization; package electrosphere.server.content.serialization;
import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -31,7 +32,7 @@ public class ContentSerialization {
* @param entities The entities * @param entities The entities
* @return The content serialization * @return The content serialization
*/ */
public static ContentSerialization constructContentSerialization(List<Entity> entities){ public static ContentSerialization constructContentSerialization(Collection<Entity> entities){
ContentSerialization rVal = new ContentSerialization(); ContentSerialization rVal = new ContentSerialization();
for(Entity entity : entities){ for(Entity entity : entities){
if(!CreatureUtils.hasControllerPlayerId(entity)){ if(!CreatureUtils.hasControllerPlayerId(entity)){

View File

@ -19,6 +19,9 @@ public class EntityDataCellMapper {
* @param serverDataCell The server data cell to register this entity to * @param serverDataCell The server data cell to register this entity to
*/ */
public void registerEntity(Entity entity, ServerDataCell serverDataCell){ public void registerEntity(Entity entity, ServerDataCell serverDataCell){
if(serverDataCell == null){
throw new Error("Mapping entity to null!");
}
entityDataCellMap.put(entity, serverDataCell); entityDataCellMap.put(entity, serverDataCell);
} }

View File

@ -1,12 +1,13 @@
package electrosphere.server.datacell; package electrosphere.server.datacell;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; 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.CopyOnWriteArraySet;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import org.joml.Vector3d; import org.joml.Vector3d;
@ -50,34 +51,71 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
*/ */
public static final int MAX_GRID_SIZE = TerrainModel.MAX_MACRO_DATA_SIZE * TerrainModel.DEFAULT_MACRO_DATA_SCALE * ServerTerrainChunk.CHUNK_DIMENSION; public static final int MAX_GRID_SIZE = TerrainModel.MAX_MACRO_DATA_SIZE * TerrainModel.DEFAULT_MACRO_DATA_SCALE * ServerTerrainChunk.CHUNK_DIMENSION;
/**
* The number of frames without players that must pass before a server data cell is unloaded
*/
static final int UNLOAD_FRAME_THRESHOLD = 100;
/** /**
* Tracks whether this manager has been flagged to unload cells or not * Tracks whether this manager has been flagged to unload cells or not
*/ */
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
*/
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<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
*/
Map<ServerDataCell,Integer> cellPlayerlessFrameMap = new HashMap<ServerDataCell,Integer>(); Map<ServerDataCell,Integer> cellPlayerlessFrameMap = new HashMap<ServerDataCell,Integer>();
//The number of frames without players that must pass before a server data cell is unloaded
static final int UNLOAD_FRAME_THRESHOLD = 100; /**
//loaded cells * Loaded cells
*/
Semaphore loadedCellsLock = new Semaphore(1); Semaphore loadedCellsLock = new Semaphore(1);
Set<ServerDataCell> loadedCells = new CopyOnWriteArraySet<ServerDataCell>();
//parent realm /**
* Parent realm
*/
Realm parent; Realm parent;
//the world data of the parent
/**
* The world data of the parent
*/
ServerWorldData serverWorldData; ServerWorldData serverWorldData;
//Manager for terrain for this particular cell manager
/**
* Manager for terrain for this particular cell manager
*/
ServerTerrainManager serverTerrainManager; ServerTerrainManager serverTerrainManager;
//manager for fluids for this particular cell manager
/**
* Manager for fluids for this particular cell manager
*/
ServerFluidManager serverFluidManager; ServerFluidManager serverFluidManager;
//lock for terrain editing
/**
* Lock for terrain editing
*/
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
*/
ServerContentManager serverContentManager; ServerContentManager serverContentManager;
/**
* Used for cleaning server data cells no longer in use from the realm
*/
Set<ServerDataCell> toCleanQueue = new HashSet<ServerDataCell>();
/** /**
* Map of world position key -> physics cell * Map of world position key -> physics cell
*/ */
@ -132,22 +170,21 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
){ ){
Vector3i targetPos = new Vector3i(x,y,z); Vector3i targetPos = new Vector3i(x,y,z);
LoggerInterface.loggerEngine.DEBUG("GriddedDataCellManager: Add player to " + x + " " + y + " " + z); LoggerInterface.loggerEngine.DEBUG("GriddedDataCellManager: Add player to " + x + " " + y + " " + z);
loadedCellsLock.acquireUninterruptibly();
if(groundDataCells.get(getServerDataCellKey(targetPos)) != null){ if(groundDataCells.get(getServerDataCellKey(targetPos)) != null){
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player); groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
} else { } else {
LoggerInterface.loggerEngine.DEBUG("Creating new cell @ " + x + " " + y + " " + z); LoggerInterface.loggerEngine.DEBUG("Creating new cell @ " + x + " " + y + " " + z);
//create data cell //create data cell
createServerDataCell(targetPos); this.createServerDataCell(targetPos);
///generates physics for the cell in a dedicated thread then finally registers ///generates physics for the cell in a dedicated thread then finally registers
runPhysicsGenerationThread(targetPos); this.runPhysicsGenerationThread(targetPos);
//add to loaded cells //add to loaded cells
loadedCellsLock.acquireUninterruptibly(); cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(targetPos)),0);
loadedCells.add(groundDataCells.get(getServerDataCellKey(targetPos)));
cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(targetPos)),0);
loadedCellsLock.release();
//add player //add player
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player); groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
} }
loadedCellsLock.release();
} }
} }
} }
@ -163,36 +200,29 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
int playerSimulationRadius = player.getSimulationRadius(); int playerSimulationRadius = player.getSimulationRadius();
Vector3i oldPosition = player.getWorldPos(); Vector3i oldPosition = player.getWorldPos();
player.setWorldPos(newPosition); player.setWorldPos(newPosition);
// System.out.println("=======" + "SET" + newX + " " + newY + " FROM " + oldX + " " + oldY + "========"); for(ServerDataCell cell : this.groundDataCells.values()){
// int removals = 0; Vector3i worldPos = this.getCellWorldPosition(cell);
// int additions = 0; if(
for(int x = oldPosition.x - playerSimulationRadius; x < oldPosition.x + playerSimulationRadius + 1; x++){ cell.containsPlayer(player) &&
for(int y = oldPosition.y - playerSimulationRadius; y < oldPosition.y + playerSimulationRadius + 1; y++){ (
for(int z = oldPosition.z - playerSimulationRadius; z < oldPosition.z + playerSimulationRadius + 1; z++){ worldPos.x < newPosition.x - playerSimulationRadius ||
if( worldPos.x > newPosition.x + playerSimulationRadius ||
x >= 0 && x < this.serverWorldData.getWorldSizeDiscrete() && worldPos.y < newPosition.y - playerSimulationRadius ||
y >= 0 && y < this.serverWorldData.getWorldSizeDiscrete() && worldPos.y > newPosition.y + playerSimulationRadius ||
z >= 0 && z < this.serverWorldData.getWorldSizeDiscrete() && worldPos.z < newPosition.z - playerSimulationRadius ||
( worldPos.z > newPosition.z + playerSimulationRadius
x < newPosition.x - playerSimulationRadius || )
x > newPosition.x + playerSimulationRadius || ){
y < newPosition.y - playerSimulationRadius || cell.removePlayer(player);
y > newPosition.y + playerSimulationRadius || this.broadcastDestructionToPlayer(player, cell);
z < newPosition.z - playerSimulationRadius || if(cell.getScene().containsEntity(player.getPlayerEntity())){
z > newPosition.z + playerSimulationRadius throw new Error(
) "Unregistering player from cell that contains player's entity!\n " +
){ player + "\n " +
Vector3i targetPos = new Vector3i(x,y,z); worldPos + "\n " +
Long key = this.getServerDataCellKey(targetPos); player.getPlayerEntity() + "\n " +
if( EntityUtils.getPosition(player.getPlayerEntity())
groundDataCells.get(key) != null && );
groundDataCells.get(key).containsPlayer(player)
){
// removals++;
groundDataCells.get(key).removePlayer(player);
this.broadcastDestructionToPlayer(player, groundDataCells.get(key));
}
}
} }
} }
} }
@ -213,31 +243,26 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
) )
){ ){
Vector3i targetPos = new Vector3i(x,y,z); Vector3i targetPos = new Vector3i(x,y,z);
// System.out.println("Add player to " + x + " " + y);
if(groundDataCells.get(getServerDataCellKey(targetPos)) != null){ if(groundDataCells.get(getServerDataCellKey(targetPos)) != null){
loadedCellsLock.acquireUninterruptibly();
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player); groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
loadedCellsLock.release();
} else { } else {
loadedCellsLock.acquireUninterruptibly();
//create data cell //create data cell
createServerDataCell(targetPos); createServerDataCell(targetPos);
//generates physics for the cell in a dedicated thread then finally registers //generates physics for the cell in a dedicated thread then finally registers
runPhysicsGenerationThread(targetPos); runPhysicsGenerationThread(targetPos);
//add to loaded cells //add to loaded cells
loadedCellsLock.acquireUninterruptibly();
loadedCells.add(groundDataCells.get(getServerDataCellKey(targetPos)));
cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(targetPos)),0); cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(targetPos)),0);
loadedCellsLock.release();
//add player //add player
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player); groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
loadedCellsLock.release();
} }
// additions++;
} else {
// System.out.println(x + "\t" + (oldX - playerSimulationRadius) + "\t" + (oldX + playerSimulationRadius));
// System.out.println(y + "\t" + (oldY - playerSimulationRadius) + "\t" + (oldY + playerSimulationRadius));
} }
} }
} }
} }
// System.out.println("removals: " + removals + "\tadditions: " + additions);
} }
/** /**
@ -280,25 +305,80 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
int currentWorldX = parent.getServerWorldData().convertRealToChunkSpace(position.x); int currentWorldX = parent.getServerWorldData().convertRealToChunkSpace(position.x);
int currentWorldY = parent.getServerWorldData().convertRealToChunkSpace(position.y); int currentWorldY = parent.getServerWorldData().convertRealToChunkSpace(position.y);
int currentWorldZ = parent.getServerWorldData().convertRealToChunkSpace(position.z); int currentWorldZ = parent.getServerWorldData().convertRealToChunkSpace(position.z);
if(currentWorldX != player.getWorldPos().x || currentWorldY != player.getWorldPos().y || currentWorldZ != player.getWorldPos().z){ Vector3i newPosition = new Vector3i(currentWorldX,currentWorldY,currentWorldZ);
movePlayer(player,new Vector3i(currentWorldX,currentWorldY,currentWorldZ)); player.setWorldPos(newPosition);
playerChangedChunk = true;
int playerSimulationRadius = player.getSimulationRadius();
//remove from cells that are out of range
for(ServerDataCell cell : this.groundDataCells.values()){
Vector3i cellWorldPos = this.getCellWorldPosition(cell);
if(
cell.containsPlayer(player) &&
(
cellWorldPos.x < newPosition.x - playerSimulationRadius ||
cellWorldPos.x > newPosition.x + playerSimulationRadius ||
cellWorldPos.y < newPosition.y - playerSimulationRadius ||
cellWorldPos.y > newPosition.y + playerSimulationRadius ||
cellWorldPos.z < newPosition.z - playerSimulationRadius ||
cellWorldPos.z > newPosition.z + playerSimulationRadius
)
){
if(cell.getScene().containsEntity(player.getPlayerEntity())){
throw new Error("Trying to remove player from a cell that contains its entity!");
}
cell.removePlayer(player);
this.broadcastDestructionToPlayer(player, cell);
}
}
//Add to cells that are in range
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.x - playerSimulationRadius + 1; z < newPosition.z + playerSimulationRadius; z++){
if(
x >= 0 && x < this.serverWorldData.getWorldSizeDiscrete() &&
y >= 0 && y < this.serverWorldData.getWorldSizeDiscrete() &&
z >= 0 && z < this.serverWorldData.getWorldSizeDiscrete()
){
Vector3i targetPos = new Vector3i(x,y,z);
if(groundDataCells.get(this.getServerDataCellKey(targetPos)) != null){
loadedCellsLock.acquireUninterruptibly();
ServerDataCell cell = groundDataCells.get(this.getServerDataCellKey(targetPos));
if(!cell.containsPlayer(player)){
cell.addPlayer(player);
}
loadedCellsLock.release();
} else {
loadedCellsLock.acquireUninterruptibly();
//create data cell
this.createServerDataCell(targetPos);
//generates physics for the cell in a dedicated thread then finally registers
this.runPhysicsGenerationThread(targetPos);
//add to loaded cells
cellPlayerlessFrameMap.put(groundDataCells.get(this.getServerDataCellKey(targetPos)),0);
//add player
groundDataCells.get(this.getServerDataCellKey(targetPos)).addPlayer(player);
loadedCellsLock.release();
}
}
}
}
} }
} }
} }
return playerChangedChunk; return playerChangedChunk;
} }
//Used for cleaning server data cells no longer in use from the realm
Set<ServerDataCell> toCleanQueue = new HashSet<ServerDataCell>();
/** /**
* Unloads all chunks that haven't had players in them for a set amount of time * Unloads all chunks that haven't had players in them for a set amount of time
*/ */
public void unloadPlayerlessChunks(){ public void unloadPlayerlessChunks(){
if(this.unloadCells){ if(this.unloadCells){
//TODO: improve to make have less performance impact //TODO: improve to make have less performance impact
for(ServerDataCell cell : loadedCells){ loadedCellsLock.acquireUninterruptibly();
loadedCellsLock.acquireUninterruptibly(); for(ServerDataCell cell : this.groundDataCells.values()){
if(cell.getPlayers().size() < 1){ if(cell.getPlayers().size() < 1){
int frameCount = cellPlayerlessFrameMap.get(cell) + 1; int frameCount = cellPlayerlessFrameMap.get(cell) + 1;
cellPlayerlessFrameMap.put(cell,frameCount); cellPlayerlessFrameMap.put(cell,frameCount);
@ -310,11 +390,9 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
cellPlayerlessFrameMap.put(cell, 0); cellPlayerlessFrameMap.put(cell, 0);
} }
} }
loadedCellsLock.release();
} }
for(ServerDataCell cell : toCleanQueue){ for(ServerDataCell cell : toCleanQueue){
parent.deregisterCell(cell); parent.deregisterCell(cell);
loadedCells.remove(cell);
Vector3i worldPos = getCellWorldPosition(cell); Vector3i worldPos = getCellWorldPosition(cell);
Long key = getServerDataCellKey(worldPos); Long key = getServerDataCellKey(worldPos);
groundDataCells.remove(key); groundDataCells.remove(key);
@ -323,13 +401,20 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
//clear all entities in cell //clear all entities in cell
for(Entity entity : cell.getScene().getEntityList()){ for(Entity entity : cell.getScene().getEntityList()){
if(ServerPlayerViewDirTree.hasTree(entity)){ if(ServerPlayerViewDirTree.hasTree(entity)){
throw new Error("Trying to unload a player's entity! " + entity + " " + worldPos); throw new Error(
"Trying to unload a player's entity! " +
entity + "\n" +
EntityUtils.getPosition(entity) + "\n" +
serverWorldData.convertRealToWorldSpace(EntityUtils.getPosition(entity)) + "\n" +
worldPos
);
} }
ServerEntityUtils.destroyEntity(entity); ServerEntityUtils.destroyEntity(entity);
} }
//save terrain to disk //save terrain to disk
serverTerrainManager.savePositionToDisk(worldPos); serverTerrainManager.savePositionToDisk(worldPos);
} }
loadedCellsLock.release();
toCleanQueue.clear(); toCleanQueue.clear();
} }
} }
@ -342,16 +427,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
*/ */
public void evictAll(){ public void evictAll(){
//TODO: improve to make have less performance impact //TODO: improve to make have less performance impact
for(ServerDataCell cell : loadedCells){ loadedCellsLock.acquireUninterruptibly();
loadedCellsLock.acquireUninterruptibly(); for(ServerDataCell cell : this.groundDataCells.values()){
int frameCount = cellPlayerlessFrameMap.get(cell) + 1; int frameCount = cellPlayerlessFrameMap.get(cell) + 1;
cellPlayerlessFrameMap.put(cell,frameCount); cellPlayerlessFrameMap.put(cell,frameCount);
toCleanQueue.add(cell); toCleanQueue.add(cell);
loadedCellsLock.release();
} }
for(ServerDataCell cell : toCleanQueue){ for(ServerDataCell cell : toCleanQueue){
parent.deregisterCell(cell); parent.deregisterCell(cell);
loadedCells.remove(cell);
Vector3i worldPos = getCellWorldPosition(cell); Vector3i worldPos = getCellWorldPosition(cell);
Long key = getServerDataCellKey(worldPos); Long key = getServerDataCellKey(worldPos);
groundDataCells.remove(key); groundDataCells.remove(key);
@ -362,6 +445,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
ServerEntityUtils.destroyEntity(entity); ServerEntityUtils.destroyEntity(entity);
} }
} }
loadedCellsLock.release();
this.serverTerrainManager.evictAll(); this.serverTerrainManager.evictAll();
toCleanQueue.clear(); toCleanQueue.clear();
} }
@ -420,13 +504,12 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
//isn't null //isn't null
groundDataCells.get(this.getServerDataCellKey(worldPos)) == null groundDataCells.get(this.getServerDataCellKey(worldPos)) == null
){ ){
loadedCellsLock.acquireUninterruptibly();
//create data cell //create data cell
this.createServerDataCell(worldPos); this.createServerDataCell(worldPos);
//generates physics for the cell in a dedicated thread then finally registers //generates physics for the cell in a dedicated thread then finally registers
this.runPhysicsGenerationThread(worldPos); this.runPhysicsGenerationThread(worldPos);
//add to loaded cells //add to loaded cells
loadedCellsLock.acquireUninterruptibly();
loadedCells.add(groundDataCells.get(this.getServerDataCellKey(worldPos)));
cellPlayerlessFrameMap.put(groundDataCells.get(this.getServerDataCellKey(worldPos)),0); cellPlayerlessFrameMap.put(groundDataCells.get(this.getServerDataCellKey(worldPos)),0);
loadedCellsLock.release(); loadedCellsLock.release();
} else if(groundDataCells.get(this.getServerDataCellKey(worldPos)) == null) { } else if(groundDataCells.get(this.getServerDataCellKey(worldPos)) == null) {
@ -464,7 +547,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
*/ */
public void simulate(){ public void simulate(){
loadedCellsLock.acquireUninterruptibly(); loadedCellsLock.acquireUninterruptibly();
for(ServerDataCell cell : loadedCells){ for(ServerDataCell cell : this.groundDataCells.values()){
if(Globals.microSimulation != null && Globals.microSimulation.isReady()){ if(Globals.microSimulation != null && Globals.microSimulation.isReady()){
Globals.microSimulation.simulate(cell); Globals.microSimulation.simulate(cell);
} }
@ -477,7 +560,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
} }
} }
loadedCellsLock.release(); loadedCellsLock.release();
updatePlayerPositions(); this.updatePlayerPositions();
} }
@ -536,7 +619,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
*/ */
private ServerDataCell createServerDataCell(Vector3i worldPos){ private ServerDataCell createServerDataCell(Vector3i worldPos){
ServerDataCell rVal = parent.createNewCell(); ServerDataCell rVal = parent.createNewCell();
Long cellKey = getServerDataCellKey(worldPos); Long cellKey = this.getServerDataCellKey(worldPos);
groundDataCells.put(cellKey,rVal); groundDataCells.put(cellKey,rVal);
LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + cellKey); LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + cellKey);
cellPositionMap.put(rVal,new Vector3i(worldPos)); cellPositionMap.put(rVal,new Vector3i(worldPos));
@ -674,7 +757,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
@Override @Override
public void save(String saveName) { public void save(String saveName) {
for(ServerDataCell cell : loadedCells){ for(ServerDataCell cell : this.groundDataCells.values()){
Long key = this.getServerDataCellKey(this.getCellWorldPosition(cell)); Long key = this.getServerDataCellKey(this.getCellWorldPosition(cell));
//offload all entities in cell to chunk file //offload all entities in cell to chunk file
serverContentManager.saveContentToDisk(key, cell.getScene().getEntityList()); serverContentManager.saveContentToDisk(key, cell.getScene().getEntityList());
@ -705,4 +788,12 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
return returnPos; return returnPos;
} }
/**
* Gets the set of loaded cells
* @return The set of loaded cells
*/
public Collection<ServerDataCell> getLoadedCells(){
return Collections.unmodifiableCollection(this.groundDataCells.values());
}
} }

View File

@ -150,14 +150,6 @@ public class Realm {
Globals.entityDataCellMapper.registerEntity(entity, cell); Globals.entityDataCellMapper.registerEntity(entity, cell);
} }
/**
* Gets the entity data cell mapper for this realm
* @return The entity data cell mapper for this realm
*/
public EntityDataCellMapper getEntityDataCellMapper(){
return this.entityDataCellMapper;
}
/** /**
* Gets the data cell manager for this realm * Gets the data cell manager for this realm
@ -167,14 +159,6 @@ public class Realm {
return this.dataCellManager; return this.dataCellManager;
} }
/**
* Sets the entity data cell mapper for this realm
* @param entityDataCellMapper The entity data cell mapper for this realm
*/
protected void setEntityDataCellMapper(EntityDataCellMapper entityDataCellMapper){
this.entityDataCellMapper = entityDataCellMapper;
}
/** /**
* Sets the data cell manager for this realm * Sets the data cell manager for this realm
* @param dataCellManager The data cell manager for this realm * @param dataCellManager The data cell manager for this realm

View File

@ -10,6 +10,7 @@ import org.joml.Vector3d;
import electrosphere.collision.CollisionEngine; import electrosphere.collision.CollisionEngine;
import electrosphere.collision.CollisionWorldData; import electrosphere.collision.CollisionWorldData;
import electrosphere.collision.hitbox.HitboxManager; import electrosphere.collision.hitbox.HitboxManager;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.game.server.world.ServerWorldData; import electrosphere.game.server.world.ServerWorldData;
import electrosphere.net.server.player.Player; import electrosphere.net.server.player.Player;
@ -76,10 +77,8 @@ public class RealmManager {
); );
//create function classes //create function classes
GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm); GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm);
EntityDataCellMapper entityDataCellMapper = new EntityDataCellMapper();
//add function classes to realm //add function classes to realm
realm.setDataCellManager(griddedDataCellManager); realm.setDataCellManager(griddedDataCellManager);
realm.setEntityDataCellMapper(entityDataCellMapper);
//register within the manager //register within the manager
realms.add(realm); realms.add(realm);
return realm; return realm;
@ -113,7 +112,6 @@ public class RealmManager {
//add function classes to realm //add function classes to realm
realm.setDataCellManager(ViewportDataCellManager.create(realm)); realm.setDataCellManager(ViewportDataCellManager.create(realm));
realm.setEntityDataCellMapper(new EntityDataCellMapper());
//register //register
realms.add(realm); realms.add(realm);

View File

@ -22,7 +22,7 @@ import java.util.Set;
* of simulation. It just acts as an object to relate players and entities by location. * of simulation. It just acts as an object to relate players and entities by location.
* This SHOULD be used for networking purposes. This is the mechanism to scope * This SHOULD be used for networking purposes. This is the mechanism to scope
* network messages by location. If you are looking for something closer to a scene from * network messages by location. If you are looking for something closer to a scene from
* a traditional game engine, EntityManager is effectively a scene for all intents and * a traditional game engine, Realm is effectively a scene for all intents and
* purposes. * purposes.
* *
*/ */
@ -62,9 +62,9 @@ public class ServerDataCell {
* @param p * @param p
*/ */
public void addPlayer(Player p){ public void addPlayer(Player p){
if(!activePlayers.contains(p)){ if(!this.containsPlayer(p)){
activePlayers.add(p); activePlayers.add(p);
serializeStateToPlayer(p); this.serializeStateToPlayer(p);
} }
} }
@ -134,7 +134,7 @@ public class ServerDataCell {
*/ */
void serializeStateToPlayer(Player player){ void serializeStateToPlayer(Player player){
for(Entity entity : scene.getEntityList()){ for(Entity entity : scene.getEntityList()){
serializeEntityToPlayer(entity,player); this.serializeEntityToPlayer(entity,player);
} }
} }
@ -144,21 +144,23 @@ public class ServerDataCell {
* @param player The player to send the entity to * @param player The player to send the entity to
*/ */
void serializeEntityToPlayer(Entity entity, Player player){ void serializeEntityToPlayer(Entity entity, Player player){
EntityType type = CommonEntityUtils.getEntityType(entity); if(!player.hasSentPlayerEntity() || player.getPlayerEntity() == null || player.getPlayerEntity() != entity){
if(type != null){ EntityType type = CommonEntityUtils.getEntityType(entity);
switch(type){ if(type != null){
case CREATURE: { switch(type){
CreatureUtils.sendEntityToPlayer(player, entity); case CREATURE: {
} break; CreatureUtils.sendEntityToPlayer(player, entity);
case ITEM: { } break;
ItemUtils.sendEntityToPlayer(player, entity); case ITEM: {
} break; ItemUtils.sendEntityToPlayer(player, entity);
case FOLIAGE: { } break;
FoliageUtils.sendFoliageToPlayer(player, entity); case FOLIAGE: {
} break; FoliageUtils.sendFoliageToPlayer(player, entity);
case COMMON: { } break;
CommonEntityUtils.sendEntityToPlayer(player, entity); case COMMON: {
} break; CommonEntityUtils.sendEntityToPlayer(player, entity);
} break;
}
} }
} }
} }
@ -181,32 +183,42 @@ public class ServerDataCell {
* @param newCell The new datacell it's moving to * @param newCell The new datacell it's moving to
*/ */
public static void moveEntityFromCellToCell(Entity entity, ServerDataCell oldCell, ServerDataCell newCell){ public static void moveEntityFromCellToCell(Entity entity, ServerDataCell oldCell, ServerDataCell newCell){
//swap which holds the entity if(entity == null){
if(oldCell != null){ throw new Error("Passed null entity! " + entity);
oldCell.getScene().deregisterEntity(entity);
} }
if(oldCell == null){
throw new Error("Passed null oldCell! " + oldCell);
}
if(newCell == null){
throw new Error("Passed null newCell! " + newCell);
}
//swap which holds the entity
oldCell.getScene().deregisterEntity(entity);
newCell.getScene().registerEntity(entity); newCell.getScene().registerEntity(entity);
//update entity data cell mapper //update entity data cell mapper
Globals.entityDataCellMapper.updateEntityCell(entity, newCell); Globals.entityDataCellMapper.updateEntityCell(entity, newCell);
//send the entity to new players that should care about it //send the entity to new players that should care about it
for(Player player : newCell.activePlayers){ for(Player player : newCell.activePlayers){
if(oldCell != null){ if(player.getPlayerEntity() == null || player.getPlayerEntity() != entity){
//if the player hasn't already seen the entity, serialize it if(oldCell != null){
if(!oldCell.containsPlayer(player)){ //if the player hasn't already seen the entity, serialize it
if(!oldCell.containsPlayer(player)){
newCell.serializeEntityToPlayer(entity, player);
}
} else {
//if the entity wasn't in a previous cell, send it to all players
newCell.serializeEntityToPlayer(entity, player); newCell.serializeEntityToPlayer(entity, player);
} }
} else {
//if the entity wasn't in a previous cell, send it to all players
newCell.serializeEntityToPlayer(entity, player);
} }
} }
//delete the entity for players that dont care about it //delete the entity for players that dont care about it
if(oldCell != null){ for(Player player : oldCell.activePlayers){
for(Player player : oldCell.activePlayers){ if(
if(!newCell.containsPlayer(player)){ !newCell.containsPlayer(player) &&
//if the player isn't also in the new cell, delete the entity (player.getPlayerEntity() == null || player.getPlayerEntity() != entity)
player.addMessage(EntityMessage.constructDestroyMessage(entity.getId())); ){
} //if the player isn't also in the new cell, delete the entity
player.addMessage(EntityMessage.constructDestroyMessage(entity.getId()));
} }
} }
} }

View File

@ -29,7 +29,7 @@ public class DataCellSearchUtils {
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Trying to get entity data cell of an entity that is not assigned to a realm!")); LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Trying to get entity data cell of an entity that is not assigned to a realm!"));
return null; return null;
} }
return realm.getEntityDataCellMapper().getEntityDataCell(entity); return Globals.entityDataCellMapper.getEntityDataCell(entity);
} }
/** /**

View File

@ -1,5 +1,6 @@
package electrosphere.server.datacell.utils; package electrosphere.server.datacell.utils;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.server.datacell.ServerDataCell; import electrosphere.server.datacell.ServerDataCell;
@ -14,7 +15,7 @@ public class ServerEntityTagUtils {
* @param tag The tag * @param tag The tag
*/ */
public static void attachTagToEntity(Entity entity, String tag){ public static void attachTagToEntity(Entity entity, String tag){
ServerDataCell cell = DataCellSearchUtils.getEntityDataCell(entity); ServerDataCell cell = Globals.entityDataCellMapper.getEntityDataCell(entity);
cell.getScene().registerEntityToTag(entity, tag); cell.getScene().registerEntityToTag(entity, tag);
} }
@ -24,7 +25,7 @@ public class ServerEntityTagUtils {
* @param tag The tag * @param tag The tag
*/ */
public static void removeTagFromEntity(Entity entity, String tag){ public static void removeTagFromEntity(Entity entity, String tag){
ServerDataCell cell = DataCellSearchUtils.getEntityDataCell(entity); ServerDataCell cell = Globals.entityDataCellMapper.getEntityDataCell(entity);
cell.getScene().removeEntityFromTag(entity, tag); cell.getScene().removeEntityFromTag(entity, tag);
} }