grid manager entity and player tracking overhaul
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
This commit is contained in:
parent
e12dd55703
commit
795fbb6a1c
@ -1,6 +1,6 @@
|
||||
{
|
||||
"gameplayGenerateWorld" : false,
|
||||
"gameplayPhysicsCellRadius" : 2,
|
||||
"gameplayPhysicsCellRadius" : 3,
|
||||
|
||||
"displayWidth" : 1920,
|
||||
"displayHeight" : 1080,
|
||||
|
||||
@ -9,3 +9,8 @@ sines pulling from sines
|
||||
noise functions pulling from sines
|
||||
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
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -52,6 +52,7 @@ public class ImGuiWindowMacros {
|
||||
ImGuiRenderer.createRendererWindows();
|
||||
ImGuiTestGen.createTestGenWindows();
|
||||
ImGuiChunkMonitor.createChunkMonitorWindows();
|
||||
ImGuiGriddedManager.createGriddedManagerWindows();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,6 +189,10 @@ public class ImGuiWindowMacros {
|
||||
if(ImGui.button("Chunk Monitor")){
|
||||
ImGuiChunkMonitor.chunkMonitorWindow.setOpen(true);
|
||||
}
|
||||
//gridded data cell monitor
|
||||
if(ImGui.button("Gridded Data Cell Monitor")){
|
||||
ImGuiGriddedManager.griddedManagerWindow.setOpen(true);
|
||||
}
|
||||
//close button
|
||||
if(ImGui.button("Close")){
|
||||
mainDebugWindow.setOpen(false);
|
||||
|
||||
@ -50,10 +50,15 @@ public class EntityCreationUtils {
|
||||
throw new IllegalStateException("Failed to create a server data cell");
|
||||
}
|
||||
//register to entity data cell mapper
|
||||
realm.getEntityDataCellMapper().registerEntity(rVal, cell);
|
||||
Globals.entityDataCellMapper.registerEntity(rVal, cell);
|
||||
//enable behavior tree tracking
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -43,11 +43,11 @@ public class EntityUtils {
|
||||
Realm realm = Globals.realmManager.getEntityRealm(e);
|
||||
if(realm != null){
|
||||
//get data cell
|
||||
ServerDataCell dataCell = realm.getEntityDataCellMapper().getEntityDataCell(e);
|
||||
ServerDataCell dataCell = Globals.entityDataCellMapper.getEntityDataCell(e);
|
||||
if(dataCell != null){
|
||||
dataCell.getScene().deregisterEntity(e);
|
||||
}
|
||||
realm.getEntityDataCellMapper().ejectEntity(e);
|
||||
Globals.entityDataCellMapper.ejectEntity(e);
|
||||
}
|
||||
Globals.realmManager.removeEntity(e);
|
||||
}
|
||||
|
||||
@ -33,6 +33,9 @@ public class ServerEntityUtils {
|
||||
* @param 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
|
||||
CollisionObjUtils.serverPositionCharacter(entity, position);
|
||||
//get current server data cell
|
||||
@ -43,6 +46,9 @@ public class ServerEntityUtils {
|
||||
} else {
|
||||
//if it doesn't already exist, try creating it and if successfull move creature
|
||||
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
|
||||
realm.initializeServerSideEntity(entity, cell);
|
||||
}
|
||||
@ -54,25 +60,34 @@ public class ServerEntityUtils {
|
||||
* @param 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);
|
||||
//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);
|
||||
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(newDataCell != null){
|
||||
ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell);
|
||||
ServerBehaviorTreeUtils.updateCell(entity, oldDataCell);
|
||||
} else {
|
||||
//if it doesn't already exist, try creating it and if successfull move creature
|
||||
newDataCell = realm.getDataCellManager().tryCreateCellAtPoint(EntityUtils.getPosition(entity));
|
||||
if(newDataCell != null){
|
||||
ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell);
|
||||
ServerBehaviorTreeUtils.updateCell(entity, oldDataCell);
|
||||
if(newDataCell == null){
|
||||
newDataCell = realm.getDataCellManager().tryCreateCellAtPoint(position);
|
||||
if(newDataCell == null){
|
||||
LoggerInterface.loggerEngine.WARNING(
|
||||
"Trying to reposition entity on server when it's new cell is null!\n" +
|
||||
"Entity new position: " + position + "\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell);
|
||||
ServerBehaviorTreeUtils.updateCell(entity, oldDataCell);
|
||||
if(oldDataCell.getScene().containsEntity(entity)){
|
||||
throw new Error("Entity not removed from scene!");
|
||||
}
|
||||
}
|
||||
//reposition entity
|
||||
CollisionObjUtils.serverPositionCharacter(entity, position);
|
||||
|
||||
@ -7,6 +7,7 @@ import electrosphere.entity.btree.BehaviorTree;
|
||||
import electrosphere.entity.state.attach.AttachUtils;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@ -19,13 +20,24 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
*/
|
||||
public class Scene {
|
||||
|
||||
|
||||
/**
|
||||
* The map of id -> entity
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Scene(){
|
||||
entityIdMap = new ConcurrentHashMap<Integer,Entity>();
|
||||
tagEntityMap = new ConcurrentHashMap<String,Set<Entity>>();
|
||||
@ -53,9 +65,6 @@ public class Scene {
|
||||
* @param e The entity to register
|
||||
*/
|
||||
public void registerEntity(Entity e){
|
||||
if(!entityIdMap.containsKey(e.getId())){
|
||||
entityList.add(e);
|
||||
}
|
||||
entityIdMap.put(e.getId(), e);
|
||||
}
|
||||
|
||||
@ -101,7 +110,6 @@ public class Scene {
|
||||
tagEntityMap.get(key).remove(e);
|
||||
}
|
||||
entityIdMap.remove(e.getId());
|
||||
entityList.remove(e);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -112,10 +120,10 @@ public class Scene {
|
||||
if(AttachUtils.hasChildren(target)){
|
||||
List<Entity> childrenList = AttachUtils.getChildrenList(target);
|
||||
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
|
||||
* @return The list of all entities in the scene
|
||||
* Gets the collection of all entities in the scene
|
||||
* @return The collection of all entities in the scene
|
||||
*/
|
||||
public List<Entity> getEntityList(){
|
||||
return entityList;
|
||||
public Collection<Entity> getEntityList(){
|
||||
return this.entityIdMap.values();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -178,7 +186,7 @@ public class Scene {
|
||||
*/
|
||||
public void describeScene(){
|
||||
LoggerInterface.loggerEngine.WARNING("Entities present in scene:");
|
||||
for(Entity entity : this.entityList){
|
||||
for(Entity entity : this.entityIdMap.values()){
|
||||
LoggerInterface.loggerEngine.WARNING(entity.getId() + "");
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,6 +166,9 @@ public class InventoryUtils {
|
||||
* @return The in-inventory 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 itemIsItem = ItemUtils.isItem(item);
|
||||
boolean hasInventory = hasNaturalInventory(creature);
|
||||
@ -360,7 +363,7 @@ public class InventoryUtils {
|
||||
Realm realm = Globals.realmManager.getEntityRealm(realWorldItem);
|
||||
if(realm != null){
|
||||
//get closest chunk
|
||||
ServerDataCell dataCell = realm.getEntityDataCellMapper().getEntityDataCell(realWorldItem);
|
||||
ServerDataCell dataCell = Globals.entityDataCellMapper.getEntityDataCell(realWorldItem);
|
||||
//broadcast destroy item
|
||||
NetworkMessage unequipMessage = InventoryMessage.constructserverCommandUnequipItemMessage(creature.getId(), InventoryProtocol.INVENTORY_TYPE_EQUIP, inventorySlot);
|
||||
dataCell.broadcastNetworkMessage(unequipMessage);
|
||||
|
||||
@ -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 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
|
||||
switch(state){
|
||||
|
||||
@ -65,6 +65,11 @@ public class CollisionObjUtils {
|
||||
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){
|
||||
EntityUtils.getPosition(e).set(position);
|
||||
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){
|
||||
EntityUtils.getPosition(e).set(position);
|
||||
DBody body = PhysicsEntityUtils.getDBody(e);
|
||||
|
||||
@ -689,6 +689,10 @@ public class CommonEntityUtils {
|
||||
ServerEntityTagUtils.attachTagToEntity(entity, EntityTags.LIFE_STATE);
|
||||
}
|
||||
|
||||
if(Globals.entityDataCellMapper.getEntityDataCell(entity) == null){
|
||||
throw new Error("Failed to map entity to cell!");
|
||||
}
|
||||
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
@ -402,6 +402,13 @@ public class CreatureUtils {
|
||||
if(CreatureUtils.hasControllerPlayerId(creature)){
|
||||
LoggerInterface.loggerNetworking.INFO("Sending controller packets");
|
||||
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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -53,6 +53,11 @@ public class Player {
|
||||
* The player's primary entity
|
||||
*/
|
||||
Entity playerEntity;
|
||||
|
||||
/**
|
||||
* Tracks whether the player's entity has been sent or not
|
||||
*/
|
||||
boolean hasSentPlayerEntity = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@ -151,6 +156,24 @@ public class Player {
|
||||
idIncrementerLock.release();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -64,14 +64,16 @@ public class ServerContentGenerator {
|
||||
double scale = foliageDescription.getScale();
|
||||
double regularity = foliageDescription.getRegularity();
|
||||
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()));
|
||||
FoliageUtils.serverSpawnTreeFoliage(
|
||||
realm,
|
||||
new Vector3d(
|
||||
realm.getServerWorldData().convertVoxelToRealSpace(x, worldPos.x),
|
||||
realX,
|
||||
height,
|
||||
realm.getServerWorldData().convertVoxelToRealSpace(z, worldPos.z)
|
||||
realZ
|
||||
),
|
||||
type,
|
||||
random.nextLong()
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package electrosphere.server.content;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.joml.Vector3i;
|
||||
@ -73,9 +74,9 @@ public class ServerContentManager {
|
||||
/**
|
||||
* Saves entity content to disk
|
||||
* @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);
|
||||
String dirPath = SaveUtils.deriveSaveDirectoryPath(Globals.currentSave.getName());
|
||||
String fullPath = dirPath + "/content/" + locationKey + ".dat";
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package electrosphere.server.content.serialization;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
@ -31,7 +32,7 @@ public class ContentSerialization {
|
||||
* @param entities The entities
|
||||
* @return The content serialization
|
||||
*/
|
||||
public static ContentSerialization constructContentSerialization(List<Entity> entities){
|
||||
public static ContentSerialization constructContentSerialization(Collection<Entity> entities){
|
||||
ContentSerialization rVal = new ContentSerialization();
|
||||
for(Entity entity : entities){
|
||||
if(!CreatureUtils.hasControllerPlayerId(entity)){
|
||||
|
||||
@ -19,6 +19,9 @@ public class EntityDataCellMapper {
|
||||
* @param serverDataCell The server data cell to register this entity to
|
||||
*/
|
||||
public void registerEntity(Entity entity, ServerDataCell serverDataCell){
|
||||
if(serverDataCell == null){
|
||||
throw new Error("Mapping entity to null!");
|
||||
}
|
||||
entityDataCellMap.put(entity, serverDataCell);
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
package electrosphere.server.datacell;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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 of server cell to its world position
|
||||
*/
|
||||
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>();
|
||||
//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);
|
||||
Set<ServerDataCell> loadedCells = new CopyOnWriteArraySet<ServerDataCell>();
|
||||
//parent realm
|
||||
|
||||
/**
|
||||
* Parent realm
|
||||
*/
|
||||
Realm parent;
|
||||
//the world data of the parent
|
||||
|
||||
/**
|
||||
* The world data of the parent
|
||||
*/
|
||||
ServerWorldData serverWorldData;
|
||||
//Manager for terrain for this particular cell manager
|
||||
|
||||
/**
|
||||
* Manager for terrain for this particular cell manager
|
||||
*/
|
||||
ServerTerrainManager serverTerrainManager;
|
||||
//manager for fluids for this particular cell manager
|
||||
|
||||
/**
|
||||
* Manager for fluids for this particular cell manager
|
||||
*/
|
||||
ServerFluidManager serverFluidManager;
|
||||
//lock for terrain editing
|
||||
|
||||
/**
|
||||
* Lock for terrain editing
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@ -132,22 +170,21 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
){
|
||||
Vector3i targetPos = new Vector3i(x,y,z);
|
||||
LoggerInterface.loggerEngine.DEBUG("GriddedDataCellManager: Add player to " + x + " " + y + " " + z);
|
||||
loadedCellsLock.acquireUninterruptibly();
|
||||
if(groundDataCells.get(getServerDataCellKey(targetPos)) != null){
|
||||
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
|
||||
} else {
|
||||
LoggerInterface.loggerEngine.DEBUG("Creating new cell @ " + x + " " + y + " " + z);
|
||||
//create data cell
|
||||
createServerDataCell(targetPos);
|
||||
this.createServerDataCell(targetPos);
|
||||
///generates physics for the cell in a dedicated thread then finally registers
|
||||
runPhysicsGenerationThread(targetPos);
|
||||
this.runPhysicsGenerationThread(targetPos);
|
||||
//add to loaded cells
|
||||
loadedCellsLock.acquireUninterruptibly();
|
||||
loadedCells.add(groundDataCells.get(getServerDataCellKey(targetPos)));
|
||||
cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(targetPos)),0);
|
||||
loadedCellsLock.release();
|
||||
cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(targetPos)),0);
|
||||
//add player
|
||||
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
|
||||
}
|
||||
loadedCellsLock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -163,36 +200,29 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
int playerSimulationRadius = player.getSimulationRadius();
|
||||
Vector3i oldPosition = player.getWorldPos();
|
||||
player.setWorldPos(newPosition);
|
||||
// System.out.println("=======" + "SET" + newX + " " + newY + " FROM " + oldX + " " + oldY + "========");
|
||||
// int removals = 0;
|
||||
// int additions = 0;
|
||||
for(int x = oldPosition.x - playerSimulationRadius; x < oldPosition.x + playerSimulationRadius + 1; x++){
|
||||
for(int y = oldPosition.y - playerSimulationRadius; y < oldPosition.y + playerSimulationRadius + 1; y++){
|
||||
for(int z = oldPosition.z - playerSimulationRadius; z < oldPosition.z + playerSimulationRadius + 1; z++){
|
||||
if(
|
||||
x >= 0 && x < this.serverWorldData.getWorldSizeDiscrete() &&
|
||||
y >= 0 && y < this.serverWorldData.getWorldSizeDiscrete() &&
|
||||
z >= 0 && z < this.serverWorldData.getWorldSizeDiscrete() &&
|
||||
(
|
||||
x < newPosition.x - playerSimulationRadius ||
|
||||
x > newPosition.x + playerSimulationRadius ||
|
||||
y < newPosition.y - playerSimulationRadius ||
|
||||
y > newPosition.y + playerSimulationRadius ||
|
||||
z < newPosition.z - playerSimulationRadius ||
|
||||
z > newPosition.z + playerSimulationRadius
|
||||
)
|
||||
){
|
||||
Vector3i targetPos = new Vector3i(x,y,z);
|
||||
Long key = this.getServerDataCellKey(targetPos);
|
||||
if(
|
||||
groundDataCells.get(key) != null &&
|
||||
groundDataCells.get(key).containsPlayer(player)
|
||||
){
|
||||
// removals++;
|
||||
groundDataCells.get(key).removePlayer(player);
|
||||
this.broadcastDestructionToPlayer(player, groundDataCells.get(key));
|
||||
}
|
||||
}
|
||||
for(ServerDataCell cell : this.groundDataCells.values()){
|
||||
Vector3i worldPos = this.getCellWorldPosition(cell);
|
||||
if(
|
||||
cell.containsPlayer(player) &&
|
||||
(
|
||||
worldPos.x < newPosition.x - playerSimulationRadius ||
|
||||
worldPos.x > newPosition.x + playerSimulationRadius ||
|
||||
worldPos.y < newPosition.y - playerSimulationRadius ||
|
||||
worldPos.y > newPosition.y + playerSimulationRadius ||
|
||||
worldPos.z < newPosition.z - playerSimulationRadius ||
|
||||
worldPos.z > newPosition.z + playerSimulationRadius
|
||||
)
|
||||
){
|
||||
cell.removePlayer(player);
|
||||
this.broadcastDestructionToPlayer(player, cell);
|
||||
if(cell.getScene().containsEntity(player.getPlayerEntity())){
|
||||
throw new Error(
|
||||
"Unregistering player from cell that contains player's entity!\n " +
|
||||
player + "\n " +
|
||||
worldPos + "\n " +
|
||||
player.getPlayerEntity() + "\n " +
|
||||
EntityUtils.getPosition(player.getPlayerEntity())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -213,31 +243,26 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
)
|
||||
){
|
||||
Vector3i targetPos = new Vector3i(x,y,z);
|
||||
// System.out.println("Add player to " + x + " " + y);
|
||||
if(groundDataCells.get(getServerDataCellKey(targetPos)) != null){
|
||||
loadedCellsLock.acquireUninterruptibly();
|
||||
groundDataCells.get(getServerDataCellKey(targetPos)).addPlayer(player);
|
||||
loadedCellsLock.release();
|
||||
} else {
|
||||
loadedCellsLock.acquireUninterruptibly();
|
||||
//create data cell
|
||||
createServerDataCell(targetPos);
|
||||
//generates physics for the cell in a dedicated thread then finally registers
|
||||
runPhysicsGenerationThread(targetPos);
|
||||
//add to loaded cells
|
||||
loadedCellsLock.acquireUninterruptibly();
|
||||
loadedCells.add(groundDataCells.get(getServerDataCellKey(targetPos)));
|
||||
cellPlayerlessFrameMap.put(groundDataCells.get(getServerDataCellKey(targetPos)),0);
|
||||
loadedCellsLock.release();
|
||||
//add 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 currentWorldY = parent.getServerWorldData().convertRealToChunkSpace(position.y);
|
||||
int currentWorldZ = parent.getServerWorldData().convertRealToChunkSpace(position.z);
|
||||
if(currentWorldX != player.getWorldPos().x || currentWorldY != player.getWorldPos().y || currentWorldZ != player.getWorldPos().z){
|
||||
movePlayer(player,new Vector3i(currentWorldX,currentWorldY,currentWorldZ));
|
||||
playerChangedChunk = true;
|
||||
Vector3i newPosition = new Vector3i(currentWorldX,currentWorldY,currentWorldZ);
|
||||
player.setWorldPos(newPosition);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//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
|
||||
*/
|
||||
public void unloadPlayerlessChunks(){
|
||||
if(this.unloadCells){
|
||||
//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){
|
||||
int frameCount = cellPlayerlessFrameMap.get(cell) + 1;
|
||||
cellPlayerlessFrameMap.put(cell,frameCount);
|
||||
@ -310,11 +390,9 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
cellPlayerlessFrameMap.put(cell, 0);
|
||||
}
|
||||
}
|
||||
loadedCellsLock.release();
|
||||
}
|
||||
for(ServerDataCell cell : toCleanQueue){
|
||||
parent.deregisterCell(cell);
|
||||
loadedCells.remove(cell);
|
||||
Vector3i worldPos = getCellWorldPosition(cell);
|
||||
Long key = getServerDataCellKey(worldPos);
|
||||
groundDataCells.remove(key);
|
||||
@ -323,13 +401,20 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
//clear all entities in cell
|
||||
for(Entity entity : cell.getScene().getEntityList()){
|
||||
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);
|
||||
}
|
||||
//save terrain to disk
|
||||
serverTerrainManager.savePositionToDisk(worldPos);
|
||||
}
|
||||
loadedCellsLock.release();
|
||||
toCleanQueue.clear();
|
||||
}
|
||||
}
|
||||
@ -342,16 +427,14 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
*/
|
||||
public void evictAll(){
|
||||
//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;
|
||||
cellPlayerlessFrameMap.put(cell,frameCount);
|
||||
toCleanQueue.add(cell);
|
||||
loadedCellsLock.release();
|
||||
}
|
||||
for(ServerDataCell cell : toCleanQueue){
|
||||
parent.deregisterCell(cell);
|
||||
loadedCells.remove(cell);
|
||||
Vector3i worldPos = getCellWorldPosition(cell);
|
||||
Long key = getServerDataCellKey(worldPos);
|
||||
groundDataCells.remove(key);
|
||||
@ -362,6 +445,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
ServerEntityUtils.destroyEntity(entity);
|
||||
}
|
||||
}
|
||||
loadedCellsLock.release();
|
||||
this.serverTerrainManager.evictAll();
|
||||
toCleanQueue.clear();
|
||||
}
|
||||
@ -420,13 +504,12 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
//isn't null
|
||||
groundDataCells.get(this.getServerDataCellKey(worldPos)) == null
|
||||
){
|
||||
loadedCellsLock.acquireUninterruptibly();
|
||||
//create data cell
|
||||
this.createServerDataCell(worldPos);
|
||||
//generates physics for the cell in a dedicated thread then finally registers
|
||||
this.runPhysicsGenerationThread(worldPos);
|
||||
//add to loaded cells
|
||||
loadedCellsLock.acquireUninterruptibly();
|
||||
loadedCells.add(groundDataCells.get(this.getServerDataCellKey(worldPos)));
|
||||
cellPlayerlessFrameMap.put(groundDataCells.get(this.getServerDataCellKey(worldPos)),0);
|
||||
loadedCellsLock.release();
|
||||
} else if(groundDataCells.get(this.getServerDataCellKey(worldPos)) == null) {
|
||||
@ -464,7 +547,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
*/
|
||||
public void simulate(){
|
||||
loadedCellsLock.acquireUninterruptibly();
|
||||
for(ServerDataCell cell : loadedCells){
|
||||
for(ServerDataCell cell : this.groundDataCells.values()){
|
||||
if(Globals.microSimulation != null && Globals.microSimulation.isReady()){
|
||||
Globals.microSimulation.simulate(cell);
|
||||
}
|
||||
@ -477,7 +560,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
}
|
||||
}
|
||||
loadedCellsLock.release();
|
||||
updatePlayerPositions();
|
||||
this.updatePlayerPositions();
|
||||
}
|
||||
|
||||
|
||||
@ -536,7 +619,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
*/
|
||||
private ServerDataCell createServerDataCell(Vector3i worldPos){
|
||||
ServerDataCell rVal = parent.createNewCell();
|
||||
Long cellKey = getServerDataCellKey(worldPos);
|
||||
Long cellKey = this.getServerDataCellKey(worldPos);
|
||||
groundDataCells.put(cellKey,rVal);
|
||||
LoggerInterface.loggerEngine.DEBUG("Create server data cell with key " + cellKey);
|
||||
cellPositionMap.put(rVal,new Vector3i(worldPos));
|
||||
@ -674,7 +757,7 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
|
||||
@Override
|
||||
public void save(String saveName) {
|
||||
for(ServerDataCell cell : loadedCells){
|
||||
for(ServerDataCell cell : this.groundDataCells.values()){
|
||||
Long key = this.getServerDataCellKey(this.getCellWorldPosition(cell));
|
||||
//offload all entities in cell to chunk file
|
||||
serverContentManager.saveContentToDisk(key, cell.getScene().getEntityList());
|
||||
@ -705,4 +788,12 @@ public class GriddedDataCellManager implements DataCellManager, VoxelCellManager
|
||||
return returnPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of loaded cells
|
||||
* @return The set of loaded cells
|
||||
*/
|
||||
public Collection<ServerDataCell> getLoadedCells(){
|
||||
return Collections.unmodifiableCollection(this.groundDataCells.values());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -150,14 +150,6 @@ public class Realm {
|
||||
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
|
||||
@ -167,14 +159,6 @@ public class Realm {
|
||||
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
|
||||
* @param dataCellManager The data cell manager for this realm
|
||||
|
||||
@ -10,6 +10,7 @@ import org.joml.Vector3d;
|
||||
import electrosphere.collision.CollisionEngine;
|
||||
import electrosphere.collision.CollisionWorldData;
|
||||
import electrosphere.collision.hitbox.HitboxManager;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.game.server.world.ServerWorldData;
|
||||
import electrosphere.net.server.player.Player;
|
||||
@ -76,10 +77,8 @@ public class RealmManager {
|
||||
);
|
||||
//create function classes
|
||||
GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm);
|
||||
EntityDataCellMapper entityDataCellMapper = new EntityDataCellMapper();
|
||||
//add function classes to realm
|
||||
realm.setDataCellManager(griddedDataCellManager);
|
||||
realm.setEntityDataCellMapper(entityDataCellMapper);
|
||||
//register within the manager
|
||||
realms.add(realm);
|
||||
return realm;
|
||||
@ -113,7 +112,6 @@ public class RealmManager {
|
||||
|
||||
//add function classes to realm
|
||||
realm.setDataCellManager(ViewportDataCellManager.create(realm));
|
||||
realm.setEntityDataCellMapper(new EntityDataCellMapper());
|
||||
|
||||
//register
|
||||
realms.add(realm);
|
||||
|
||||
@ -22,7 +22,7 @@ import java.util.Set;
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
@ -62,9 +62,9 @@ public class ServerDataCell {
|
||||
* @param p
|
||||
*/
|
||||
public void addPlayer(Player p){
|
||||
if(!activePlayers.contains(p)){
|
||||
if(!this.containsPlayer(p)){
|
||||
activePlayers.add(p);
|
||||
serializeStateToPlayer(p);
|
||||
this.serializeStateToPlayer(p);
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ public class ServerDataCell {
|
||||
*/
|
||||
void serializeStateToPlayer(Player player){
|
||||
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
|
||||
*/
|
||||
void serializeEntityToPlayer(Entity entity, Player player){
|
||||
EntityType type = CommonEntityUtils.getEntityType(entity);
|
||||
if(type != null){
|
||||
switch(type){
|
||||
case CREATURE: {
|
||||
CreatureUtils.sendEntityToPlayer(player, entity);
|
||||
} break;
|
||||
case ITEM: {
|
||||
ItemUtils.sendEntityToPlayer(player, entity);
|
||||
} break;
|
||||
case FOLIAGE: {
|
||||
FoliageUtils.sendFoliageToPlayer(player, entity);
|
||||
} break;
|
||||
case COMMON: {
|
||||
CommonEntityUtils.sendEntityToPlayer(player, entity);
|
||||
} break;
|
||||
if(!player.hasSentPlayerEntity() || player.getPlayerEntity() == null || player.getPlayerEntity() != entity){
|
||||
EntityType type = CommonEntityUtils.getEntityType(entity);
|
||||
if(type != null){
|
||||
switch(type){
|
||||
case CREATURE: {
|
||||
CreatureUtils.sendEntityToPlayer(player, entity);
|
||||
} break;
|
||||
case ITEM: {
|
||||
ItemUtils.sendEntityToPlayer(player, entity);
|
||||
} break;
|
||||
case FOLIAGE: {
|
||||
FoliageUtils.sendFoliageToPlayer(player, entity);
|
||||
} break;
|
||||
case COMMON: {
|
||||
CommonEntityUtils.sendEntityToPlayer(player, entity);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,32 +183,42 @@ public class ServerDataCell {
|
||||
* @param newCell The new datacell it's moving to
|
||||
*/
|
||||
public static void moveEntityFromCellToCell(Entity entity, ServerDataCell oldCell, ServerDataCell newCell){
|
||||
//swap which holds the entity
|
||||
if(oldCell != null){
|
||||
oldCell.getScene().deregisterEntity(entity);
|
||||
if(entity == null){
|
||||
throw new Error("Passed null entity! " + 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);
|
||||
//update entity data cell mapper
|
||||
Globals.entityDataCellMapper.updateEntityCell(entity, newCell);
|
||||
//send the entity to new players that should care about it
|
||||
for(Player player : newCell.activePlayers){
|
||||
if(oldCell != null){
|
||||
//if the player hasn't already seen the entity, serialize it
|
||||
if(!oldCell.containsPlayer(player)){
|
||||
if(player.getPlayerEntity() == null || player.getPlayerEntity() != entity){
|
||||
if(oldCell != null){
|
||||
//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);
|
||||
}
|
||||
} 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
|
||||
if(oldCell != null){
|
||||
for(Player player : oldCell.activePlayers){
|
||||
if(!newCell.containsPlayer(player)){
|
||||
//if the player isn't also in the new cell, delete the entity
|
||||
player.addMessage(EntityMessage.constructDestroyMessage(entity.getId()));
|
||||
}
|
||||
for(Player player : oldCell.activePlayers){
|
||||
if(
|
||||
!newCell.containsPlayer(player) &&
|
||||
(player.getPlayerEntity() == null || player.getPlayerEntity() != entity)
|
||||
){
|
||||
//if the player isn't also in the new cell, delete the entity
|
||||
player.addMessage(EntityMessage.constructDestroyMessage(entity.getId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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!"));
|
||||
return null;
|
||||
}
|
||||
return realm.getEntityDataCellMapper().getEntityDataCell(entity);
|
||||
return Globals.entityDataCellMapper.getEntityDataCell(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package electrosphere.server.datacell.utils;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.server.datacell.ServerDataCell;
|
||||
|
||||
@ -14,7 +15,7 @@ public class ServerEntityTagUtils {
|
||||
* @param tag The 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);
|
||||
}
|
||||
|
||||
@ -24,7 +25,7 @@ public class ServerEntityTagUtils {
|
||||
* @param tag The 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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user