diff --git a/net/player.json b/net/player.json index 781946d8..af08a3f7 100644 --- a/net/player.json +++ b/net/player.json @@ -16,6 +16,10 @@ { "name" : "initialDiscretePositionY", "type" : "FIXED_INT" + }, + { + "name" : "initialDiscretePositionZ", + "type" : "FIXED_INT" } ], "messageTypes" : [ @@ -29,7 +33,8 @@ "messageName" : "SetInitialDiscretePosition", "data" : [ "initialDiscretePositionX", - "initialDiscretePositionY" + "initialDiscretePositionY", + "initialDiscretePositionZ" ] } ] diff --git a/net/terrain.json b/net/terrain.json index 9f054f09..623d7fde 100644 --- a/net/terrain.json +++ b/net/terrain.json @@ -41,6 +41,10 @@ "name" : "worldY", "type" : "FIXED_INT" }, + { + "name" : "worldZ", + "type" : "FIXED_INT" + }, { "name" : "value", "type" : "FIXED_FLOAT" @@ -57,6 +61,10 @@ "name" : "locationY", "type" : "FIXED_INT" }, + { + "name" : "locationZ", + "type" : "FIXED_INT" + }, { @@ -67,6 +75,10 @@ "name" : "realLocationY", "type" : "FIXED_DOUBLE" }, + { + "name" : "realLocationZ", + "type" : "FIXED_DOUBLE" + }, @@ -305,7 +317,8 @@ "messageName" : "Update", "data" : [ "locationX", - "locationY" + "locationY", + "locationZ" ] }, { @@ -379,15 +392,18 @@ "value", "worldX", "worldY", + "worldZ", "locationX", - "locationY" + "locationY", + "locationZ" ] }, { "messageName" : "SpawnPosition", "data" : [ "realLocationX", - "realLocationY" + "realLocationY", + "realLocationZ" ] } ] diff --git a/src/main/java/electrosphere/client/culling/ClientEntityCullingManager.java b/src/main/java/electrosphere/client/culling/ClientEntityCullingManager.java new file mode 100644 index 00000000..8605248e --- /dev/null +++ b/src/main/java/electrosphere/client/culling/ClientEntityCullingManager.java @@ -0,0 +1,85 @@ +package electrosphere.client.culling; + +import java.util.List; + +import org.joml.Vector3d; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.Scene; +import electrosphere.entity.types.attach.AttachUtils; + +public class ClientEntityCullingManager { + + Scene scene; + + public ClientEntityCullingManager(Scene scene){ + this.scene = scene; + } + + + public void recursiveHide(Entity target){ + if(AttachUtils.hasChildren(target)){ + List childrenList = AttachUtils.getChildrenList(target); + for(Entity currentChild : childrenList){ + recursiveHide(currentChild); + } + } + target.putData(EntityDataStrings.DATA_STRING_DRAW, false); + } + + public void recursiveShow(Entity target){ + if(AttachUtils.hasChildren(target)){ + List childrenList = AttachUtils.getChildrenList(target); + for(Entity currentChild : childrenList){ + recursiveShow(currentChild); + } + } + target.putData(EntityDataStrings.DATA_STRING_DRAW, true); + } + + public void clearOutOfBoundsEntities(){ + if(Globals.commonWorldData != null && Globals.playerEntity != null && Globals.clientPlayerData != null){ + Vector3d playerCharacterPos = EntityUtils.getPosition(Globals.playerEntity); + int playerCharacterWorldX = Globals.commonWorldData.convertRealToWorld(playerCharacterPos.x); + int playerCharacterWorldY = Globals.commonWorldData.convertRealToWorld(playerCharacterPos.y); + int playerCharacterWorldZ = Globals.commonWorldData.convertRealToWorld(playerCharacterPos.z); + if( + playerCharacterWorldX != Globals.clientPlayerData.getWorldPos().x|| + playerCharacterWorldY != Globals.clientPlayerData.getWorldPos().y || + playerCharacterWorldZ != Globals.clientPlayerData.getWorldPos().z + ){ + for(Entity entity : scene.getEntityList()){ + if(entity.containsKey(EntityDataStrings.TERRAIN_IS_TERRAIN) || entity.containsKey(EntityDataStrings.ATTACH_PARENT) || entity.containsKey(EntityDataStrings.COLLISION_ENTITY_PARENT)){ + + } else { + Vector3d position = EntityUtils.getPosition(entity); + //common world data is initialized with the collision data + //if this is null then the engine hasn't fully started up yet + if(position != null){ + int worldX = Globals.commonWorldData.convertRealToWorld(position.x); + int worldY = Globals.commonWorldData.convertRealToWorld(position.z); + if(!Globals.drawCellManager.coordsInPhysicsSpace(worldX, worldY)){ + //if we're running the server we need to just hide the entity + //otherwise delete it + if(Globals.RUN_SERVER && Globals.RUN_CLIENT){ + recursiveHide(entity); + } else { + scene.recursiveDeregister(entity); + } + } else { + //if the entity is within range, we're running server, + //and it's not set to visible, make it visible + if(Globals.RUN_SERVER && Globals.RUN_CLIENT){ + recursiveShow(entity); + } + } + } + } + } + } + } + } +} diff --git a/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java b/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java new file mode 100644 index 00000000..86ed2e94 --- /dev/null +++ b/src/main/java/electrosphere/client/scene/ClientSceneWrapper.java @@ -0,0 +1,98 @@ +package electrosphere.client.scene; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.Scene; +import electrosphere.game.collision.CollisionEngine; +import electrosphere.logger.LoggerInterface; + +/** + * Wrapper around the scene object to provide lots of much needed client-specific utility + * Does all the server<->client id translation and provides utilities to map between the two + */ +public class ClientSceneWrapper { + + //entity id translation between server/client + Map clientToServerIdMap = new ConcurrentHashMap(); + Map serverToClientIdMap = new ConcurrentHashMap(); + + //The scene backing the wrapper + Scene scene; + + //The engine used to back physics collision checks in client + CollisionEngine collisionEngine; + + public ClientSceneWrapper(Scene scene, CollisionEngine collisionEngine){ + this.scene = scene; + this.collisionEngine = collisionEngine; + } + + /** + * Registers a server provided ID as a mapping to a given ID on the client + * @param clientId The client's generated ID + * @param serverId The server's provided ID + */ + public void mapIdToId(int clientId, int serverId){ + LoggerInterface.loggerEngine.DEBUG("MapID: " + clientId + " <===> " + serverId); + clientToServerIdMap.put(clientId, serverId); + serverToClientIdMap.put(serverId, clientId); + } + + /** + * Resolves a client ID to the equivalent ID on the server + * @param clientId The id provided by the client + * @return The equivalent id on the server + */ + public int mapClientToServerId(int clientId){ + return clientToServerIdMap.get(clientId); + } + + /** + * Translates the id provided by the server into the equivalent id on the client + * @param serverId The id provided by the server + * @return The equivalent id on the client + */ + public int mapServerToClientId(int serverId){ + return serverToClientIdMap.get(serverId); + } + + + /** + * Returns true if the server->client map contains a given id + * @param id The id to search for + * @return True if the server->client map contains the provided id + */ + public boolean serverToClientMapContainsId(int id){ + return serverToClientIdMap.containsKey(id); + } + + + /** + * Gets the entity provided a server-provided id + * @param id The server-provided ID + * @return The entity in question + */ + public Entity getEntityFromServerId(int id){ + return scene.getEntityFromId(mapServerToClientId(id)); + } + + /** + * Gets the scene backing this client scene wrapper + * @return The scene + */ + public Scene getScene(){ + return this.scene; + } + + /** + * Gets the collision engine backing the wrapper + * @return + */ + public CollisionEngine getCollisionEngine(){ + return collisionEngine; + } + +} diff --git a/src/main/java/electrosphere/client/sim/ClientSimulation.java b/src/main/java/electrosphere/client/sim/ClientSimulation.java new file mode 100644 index 00000000..0408a8a3 --- /dev/null +++ b/src/main/java/electrosphere/client/sim/ClientSimulation.java @@ -0,0 +1,127 @@ +package electrosphere.client.sim; + +import electrosphere.engine.Globals; +import electrosphere.engine.Main; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityTags; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.collidable.ClientCollidableTree; +import electrosphere.entity.types.attach.AttachUtils; +import electrosphere.entity.types.hitbox.HitboxUtils; +import electrosphere.entity.types.item.ItemUtils; +import electrosphere.entity.types.particle.ParticleUtils; +import electrosphere.game.client.targeting.crosshair.Crosshair; +import electrosphere.renderer.actor.Actor; + +public class ClientSimulation { + + boolean isReady = false; + boolean loadTerrain = false; + + public ClientSimulation(){ + isReady = false; + } + + public void simulate(){ + //simulate bullet physics engine step + Globals.clientSceneWrapper.getCollisionEngine().simulatePhysics(Main.deltaFrames); + //update actor animations + for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE)){ + //fetch actor + Actor currentActor = EntityUtils.getActor(currentEntity); + //increment animations + if(currentActor.isPlayingAnimation()){ + currentActor.incrementAnimationTime(Main.deltaFrames / Main.targetFrameRate); + } + } + //make items play idle animation + for(Entity item : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.ITEM)){ + ItemUtils.updateItemActorAnimation(item); + } + //particle state updates + for(Entity particle : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.PARTICLE)){ + // ParticleTree tree = ParticleUtils.getParticleTree(particle); + // tree.simulate(Main.deltaFrames); + ParticleUtils.makeParticleBillboardFaceCamera(particle); + } + //update attached entity positions + AttachUtils.clientUpdateAttachedEntityPositions(); + //update hitbox positions + for(Entity currentHitbox : Globals.clientHitboxManager.getAllHitboxes()){ + HitboxUtils.clientUpdatePosition(currentHitbox); + } + //collide hitboxes + for(Entity currentHitbox : Globals.clientHitboxManager.getAllHitboxes()){ + if(isReady){ + HitboxUtils.clientCollideEntities(currentHitbox); + } + } + //tally collidables and offset position accordingly + // for(Entity currentCollidable : Globals.entityManager.getEntitiesWithTag(EntityTags.COLLIDABLE)){ + // CollidableTree tree = CollidableTree.getCollidableTree(currentCollidable); + // tree.simulate(Main.deltaFrames); + // } + //targeting crosshair + Crosshair.checkTargetable(); + Crosshair.updateTargetCrosshairPosition(); + //simulate behavior trees + Globals.clientSceneWrapper.getScene().simulateBehaviorTrees(Main.deltaFrames); + //sum collidable impulses + for(Entity collidable : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE)){ + ClientCollidableTree.getClientCollidableTree(collidable).simulate(Main.deltaFrames); + } + //clear collidable impulse lists + Globals.clientSceneWrapper.getCollisionEngine().clearCollidableImpulseLists(); + //delete all client side entities that aren't in visible chunks + if(Globals.clientEntityCullingManager != null){ + Globals.clientEntityCullingManager.clearOutOfBoundsEntities(); + } + } + + /** + * Gets whether the client simulation is ready to execute + * @return True if ready to execute, false otherwise + */ + public boolean isReady(){ + return isReady; + } + + /** + * Sets the ready status of the client simulation + * @param ready True if ready to simulate, false otherwise + */ + public void setReady(boolean ready){ + isReady = ready; + } + + /** + * Freezes simulation (sets ready to false) + */ + public void freeze(){ + isReady = false; + } + + /** + * Unfreezes simulation (sets ready to true) + */ + public void unfreeze(){ + isReady = true; + } + + /** + * Gets whether the client simulation is loading terrain + * @return True if loading terrain, false otherwise + */ + public boolean isLoadingTerrain(){ + return this.loadTerrain; + } + + /** + * Sets whether the client should load terrain or not + * @param loadTerrain True if should load terrain, false otherwise + */ + public void setLoadingTerrain(boolean loadTerrain){ + this.loadTerrain = loadTerrain; + } + +} diff --git a/src/main/java/electrosphere/controls/ControlHandler.java b/src/main/java/electrosphere/controls/ControlHandler.java index 2a6fb1d3..8ef7d9fb 100644 --- a/src/main/java/electrosphere/controls/ControlHandler.java +++ b/src/main/java/electrosphere/controls/ControlHandler.java @@ -420,7 +420,7 @@ public class ControlHandler { mainGameControlList.add(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_FORWARD)); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_FORWARD).setOnPress(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -442,7 +442,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_FORWARD).setOnRepeat(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -464,7 +464,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_FORWARD).setOnRelease(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; groundTree.slowdown(); @@ -477,7 +477,7 @@ public class ControlHandler { mainGameControlList.add(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_BACKWARD)); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_BACKWARD).setOnPress(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -496,7 +496,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_BACKWARD).setOnRepeat(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -515,7 +515,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_BACKWARD).setOnRelease(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; groundTree.slowdown(); @@ -528,7 +528,7 @@ public class ControlHandler { mainGameControlList.add(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_LEFT)); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_LEFT).setOnPress(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -544,7 +544,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_LEFT).setOnRepeat(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -560,7 +560,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_LEFT).setOnRelease(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; groundTree.slowdown(); @@ -573,7 +573,7 @@ public class ControlHandler { mainGameControlList.add(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_RIGHT)); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_RIGHT).setOnPress(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -589,7 +589,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_RIGHT).setOnRepeat(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -605,7 +605,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_RIGHT).setOnRelease(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; groundTree.slowdown(); @@ -627,7 +627,7 @@ public class ControlHandler { mainGameControlList.add(controls.get(DATA_STRING_INPUT_CODE_STRAFE_LEFT)); controls.get(DATA_STRING_INPUT_CODE_STRAFE_LEFT).setOnPress(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -644,7 +644,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_STRAFE_LEFT).setOnRepeat(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -661,7 +661,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_STRAFE_LEFT).setOnRelease(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; groundTree.slowdown(); @@ -674,7 +674,7 @@ public class ControlHandler { mainGameControlList.add(controls.get(DATA_STRING_INPUT_CODE_STRAFE_RIGHT)); controls.get(DATA_STRING_INPUT_CODE_STRAFE_RIGHT).setOnPress(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -691,7 +691,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_STRAFE_RIGHT).setOnRepeat(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); @@ -708,7 +708,7 @@ public class ControlHandler { }}); controls.get(DATA_STRING_INPUT_CODE_STRAFE_RIGHT).setOnRelease(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(Globals.playerEntity); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(Globals.playerEntity); if(movementTree instanceof GroundMovementTree){ GroundMovementTree groundTree = (GroundMovementTree) movementTree; groundTree.slowdown(); @@ -722,7 +722,7 @@ public class ControlHandler { mainGameControlList.add(controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_JUMP)); controls.get(DATA_STRING_INPUT_CODE_MOVEMENT_JUMP).setOnPress(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - JumpTree jumpTree = JumpTree.getJumpTree(Globals.playerEntity); + JumpTree jumpTree = JumpTree.getClientJumpTree(Globals.playerEntity); if(jumpTree != null){ jumpTree.start(); } @@ -734,7 +734,7 @@ public class ControlHandler { mainGameControlList.add(controls.get(INPUT_CODE_SPRINT)); controls.get(INPUT_CODE_SPRINT).setOnPress(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - SprintTree sprintTree = CreatureUtils.getSprintTree(Globals.playerEntity); + SprintTree sprintTree = CreatureUtils.clientGetSprintTree(Globals.playerEntity); if(sprintTree != null){ sprintTree.start(); } @@ -742,7 +742,7 @@ public class ControlHandler { }}); controls.get(INPUT_CODE_SPRINT).setOnRelease(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ - SprintTree sprintTree = CreatureUtils.getSprintTree(Globals.playerEntity); + SprintTree sprintTree = CreatureUtils.clientGetSprintTree(Globals.playerEntity); if(sprintTree != null){ sprintTree.stop(); } @@ -804,7 +804,7 @@ public class ControlHandler { controls.get(DATA_STRING_INPUT_CODE_ATTACK_PRIMARY).setOnPress(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ // Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); - AttackTree attackTree = CreatureUtils.getAttackTree(Globals.playerEntity); + AttackTree attackTree = CreatureUtils.clientGetAttackTree(Globals.playerEntity); if(attackTree != null){ // CreatureUtils.setFacingVector(Globals.playerCharacter, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).normalize()); attackTree.start(); @@ -826,7 +826,7 @@ public class ControlHandler { controls.get(DATA_STRING_INPUT_CODE_ATTACK_PRIMARY).setOnRelease(new ControlMethod(){public void execute(){ if(Globals.playerEntity != null){ // Vector3f cameraEyeVector = CameraEntityUtils.getCameraEye(Globals.playerCamera); - AttackTree attackTree = CreatureUtils.getAttackTree(Globals.playerEntity); + AttackTree attackTree = CreatureUtils.clientGetAttackTree(Globals.playerEntity); if(attackTree != null){ // CreatureUtils.setFacingVector(Globals.playerCharacter, new Vector3d(-cameraEyeVector.x,0,-cameraEyeVector.z).normalize()); attackTree.release(); diff --git a/src/main/java/electrosphere/engine/Globals.java b/src/main/java/electrosphere/engine/Globals.java index c5c14d7b..a08b1474 100644 --- a/src/main/java/electrosphere/engine/Globals.java +++ b/src/main/java/electrosphere/engine/Globals.java @@ -11,6 +11,9 @@ import org.lwjgl.glfw.GLFWErrorCallback; import electrosphere.audio.AudioEngine; import electrosphere.auth.AuthenticationManager; +import electrosphere.client.culling.ClientEntityCullingManager; +import electrosphere.client.scene.ClientSceneWrapper; +import electrosphere.client.sim.ClientSimulation; import electrosphere.collision.dispatch.CollisionObject; import electrosphere.controls.CameraHandler; import electrosphere.controls.ControlCallback; @@ -18,6 +21,7 @@ import electrosphere.controls.ControlHandler; import electrosphere.controls.MouseCallback; import electrosphere.engine.assetmanager.AssetDataStrings; import electrosphere.engine.assetmanager.AssetManager; +import electrosphere.engine.loadingthreads.LoadingThread; import electrosphere.entity.Entity; import electrosphere.entity.Scene; import electrosphere.entity.types.hitbox.HitboxManager; @@ -56,7 +60,10 @@ import electrosphere.renderer.ui.font.FontUtils; import electrosphere.renderer.ui.font.RawFontMap; import electrosphere.script.ScriptEngine; import electrosphere.server.ai.AIManager; -import electrosphere.server.datacell.DataCellManager; +import electrosphere.server.datacell.EntityDataCellMapper; +import electrosphere.server.datacell.GriddedDataCellManager; +import electrosphere.server.datacell.RealmManager; +import electrosphere.server.datacell.physics.DataCellPhysicsManager; import electrosphere.server.db.DatabaseController; import electrosphere.server.pathfinding.NavMeshManager; import electrosphere.server.simulation.MacroSimulation; @@ -120,12 +127,6 @@ public class Globals { public static MouseCallback mouseCallback = new MouseCallback(); - // - // Collision engine - // - public static CollisionEngine collisionEngine; - - // // Game Save stuff // @@ -149,10 +150,12 @@ public class Globals { public static CameraHandler cameraHandler = new CameraHandler(); // - //current world + //Server scene management // public static ServerWorldData serverWorldData; - public static DataCellManager dataCellManager; + public static RealmManager realmManager; + public static EntityDataCellMapper entityDataCellMapper; + public static DataCellPhysicsManager dataCellPhysicsManager; // //Player manager @@ -231,9 +234,6 @@ public class Globals { // //Engine - Main managers/variables // - //keeps track of all entities in game - public static Scene entityManager; - public static Scene clientScene; //terrain manager // public static boolean LOAD_TERRAIN = true; @@ -254,8 +254,14 @@ public class Globals { public static ScriptEngine scriptEngine; //manages hitboxes - public static HitboxManager hitboxManager; + public static HitboxManager clientHitboxManager; + //client scene management + public static Scene clientScene; + public static ClientSceneWrapper clientSceneWrapper; + public static ClientEntityCullingManager clientEntityCullingManager; + public static ClientSimulation clientSimulation; + //client world data public static ClientWorldData clientWorldData; @@ -350,8 +356,9 @@ public class Globals { //load in shader options map shaderOptionMap = FileUtils.loadObjectFromAssetPath("Shaders/shaderoptions.json", ShaderOptionMap.class); shaderOptionMap.debug(); - //create entity manager - entityManager = new Scene(); + //client scene wrapper + clientScene = new Scene(); + clientSceneWrapper = new ClientSceneWrapper(clientScene, new CollisionEngine()); //temporary hold for skybox colors skyboxColors = new ArrayList(); //load asset manager @@ -362,13 +369,19 @@ public class Globals { scriptEngine = new ScriptEngine(); scriptEngine.init(); //hitbox manager - hitboxManager = new HitboxManager(); + clientHitboxManager = new HitboxManager(); //ai manager aiManager = new AIManager(); - //collision engine - collisionEngine = new CollisionEngine(); + //data cell manager + realmManager = new RealmManager(); + // dataCellManager = new DataCellManager(); + // griddedDataCellManager = new GriddedDataCellManager(); + entityDataCellMapper = new EntityDataCellMapper(); + // dataCellLocationResolver = new DataCellLocationResolver(); //nav mesh manager navMeshManager = new NavMeshManager(); + //terrain + Globals.clientTerrainManager = new ClientTerrainManager(); //game config gameConfigDefault = electrosphere.game.data.Config.loadDefaultConfig(); gameConfigCurrent = gameConfigDefault; diff --git a/src/main/java/electrosphere/engine/LoadingThread.java b/src/main/java/electrosphere/engine/LoadingThread.java deleted file mode 100644 index 566fa73d..00000000 --- a/src/main/java/electrosphere/engine/LoadingThread.java +++ /dev/null @@ -1,1018 +0,0 @@ -package electrosphere.engine; - -import java.io.IOException; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.util.Random; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; - -import org.joml.Quaternionf; -import org.joml.Vector2i; -import org.joml.Vector3d; -import org.joml.Vector3f; - -import electrosphere.auth.AuthenticationManager; -import electrosphere.controls.ControlHandler; -import electrosphere.engine.assetmanager.AssetDataStrings; -import electrosphere.entity.Entity; -import electrosphere.entity.EntityDataStrings; -import electrosphere.entity.Scene; -import electrosphere.entity.EntityUtils; -import electrosphere.entity.scene.SceneLoader; -import electrosphere.entity.state.movement.ApplyRotationTree; -import electrosphere.entity.types.camera.CameraEntityUtils; -import electrosphere.entity.types.creature.CreatureTemplate; -import electrosphere.entity.types.creature.CreatureUtils; -import electrosphere.entity.types.item.ItemUtils; -import electrosphere.entity.types.object.ObjectUtils; -import electrosphere.entity.types.terrain.TerrainChunk; -import electrosphere.game.client.cells.DrawCellManager; -import electrosphere.game.client.targeting.crosshair.Crosshair; -import electrosphere.game.client.terrain.manager.ClientTerrainManager; -import electrosphere.game.collision.CommonWorldData; -import electrosphere.game.data.creature.type.CreatureType; -import electrosphere.game.data.creature.type.visualattribute.VisualAttribute; -import electrosphere.game.server.terrain.manager.ServerTerrainManager; -import electrosphere.game.server.town.Town; -import electrosphere.game.server.world.MacroData; -import electrosphere.game.server.world.ServerWorldData; -import electrosphere.logger.LoggerInterface; -import electrosphere.menu.MenuGenerators; -import electrosphere.menu.MenuGeneratorsMultiplayer; -import electrosphere.menu.WindowStrings; -import electrosphere.menu.WindowUtils; -import electrosphere.net.NetUtils; -import electrosphere.net.client.ClientNetworking; -import electrosphere.net.server.Server; -import electrosphere.net.server.player.Player; -import electrosphere.renderer.Model; -import electrosphere.renderer.meshgen.TreeModelGeneration; -import electrosphere.renderer.ui.Window; -import electrosphere.server.ai.creature.adventurer.SeekTown; -import electrosphere.server.datacell.DataCellManager; -import electrosphere.server.saves.SaveUtils; -import electrosphere.server.simulation.MacroSimulation; -import electrosphere.server.simulation.MicroSimulation; -import electrosphere.util.FileUtils; - -/** - * - * @author amaterasu - */ -public class LoadingThread extends Thread { - - public static final int LOAD_TITLE_MENU = 0; - public static final int LOAD_MAIN_GAME = 1; - public static final int LOAD_ARENA = 2; - public static final int LOAD_CHARACTER_SERVER = 3; - public static final int LOAD_CLIENT_WORLD = 4; - public static final int LOAD_DEBUG_RANDOM_SP_WORLD = 5; - - int threadType; - - Semaphore lock; - - public LoadingThread(int type){ - threadType = type; - lock = new Semaphore(1); - } - - @Override - public void run(){ - lock.acquireUninterruptibly(); - Window loadingWindow = (Window)Globals.elementManager.getWindow(WindowStrings.WINDOW_LOADING); - switch(threadType){ - - - - - - - - - case LOAD_TITLE_MENU: - WindowUtils.recursiveSetVisible(loadingWindow,false); - WindowUtils.focusWindow(WindowStrings.WINDOW_MENU_MAIN); - WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), true); - break; - - - - - - - - - - case LOAD_MAIN_GAME: - - - //initialize the terrain manager (server only) -// if(Globals.RUN_SERVER){ -// initServerGameTerrainManager(); -// } - - //TODO: Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,randomDampener,0); - Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,0.0f,0); - SaveUtils.loadSave(Globals.currentSaveName); - Globals.dataCellManager = new DataCellManager(Globals.serverWorldData); - //TODO: set spawnpoint - //TODO: Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); - //TODO: Globals.dataCellManager = new DataCellManager(Globals.serverWorldData); -// Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); -// Globals.dataCellManager = new DataCellManager(Globals.serverWorldData); - LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT); - //init the data of the world -// initServerGameWorldData(); - initDataCellManager(); - //init authentication - initAuthenticationManager(); - //initialize the server thread (server only) - initServerThread(); - //initialize the "virtual" objects simulation - initMacroSimulation(); - //initialize the "real" objects simulation - initMicroSimulation(); - //collision engine - initCommonWorldData(Globals.RUN_SERVER); - //init draw cell manager - initDrawCellManager(); - //init game specific stuff (ie different skybox colors) - initGameGraphicalEntities(); - //set simulations to ready if they exist - setSimulationsToReady(); - //log - LoggerInterface.loggerEngine.INFO("[Server]Finished loading main world"); - break; - - - - - - - - - - case LOAD_ARENA: - //init server arena terrain manager separately - initServerArenaTerrainManager(); - //init the data of the world - initServerArenaWorldData(); - //init data cell manager - initDataCellManager(); - //for testing purposes - FileUtils.recursivelyDelete("/Users/satellite/temp/saves/arena"); - //init database connection - SaveUtils.initSave("arena"); - //connect to database - SaveUtils.loadSave("arena"); - //init authentication - initAuthenticationManager(); - //initialize the server thread (server only) - initServerThread(); - //collision engine - initCommonWorldData(Globals.RUN_SERVER); - //init draw cell manager - initDrawCellManager(); - //initialize the "virtual" objects simulation - //not really relevant in arena mode -// initMacroSimulation(); - //initialize the "real" objects simulation - initMicroSimulation(); - //init arena specific stuff (ie different skybox colors) - initArenaGraphicalEntities(); - //create arena entities - creatingRandomEntities(); - //set simulations to ready if they exist - setSimulationsToReady(); - LoggerInterface.loggerEngine.INFO("[Server]Finished loading arena world"); - break; - - case LOAD_CHARACTER_SERVER: - WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), false); - WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); - loadingWindow.setVisible(true); - //disable menu input - Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.NO_INPUT); - //initialize the client thread (client) - initClientThread(); - //while we don't know what races are playable, wait - while(Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces().size() == 0){ - try { - TimeUnit.MILLISECONDS.sleep(5); - } catch (InterruptedException ex) {} - } - //once we have them, bring up the character creation interface - //init character creation window - //eventually should replace with at ui to select an already created character or create a new one - WindowUtils.replaceMainMenuContents(MenuGeneratorsMultiplayer.createMultiplayerCharacterCreationWindow()); - //make loading dialog disappear - loadingWindow.setVisible(false); - //make character creation window visible - WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), true); - //recapture window - Globals.controlHandler.setShouldRecapture(true); - //log - LoggerInterface.loggerEngine.INFO("[Client]Finished loading character creation menu"); - //set menu controls again - Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.TITLE_MENU); - break; - - case LOAD_CLIENT_WORLD: - WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), false); - WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); - loadingWindow.setVisible(true); - //disable menu input - Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.NO_INPUT); - //collision engine - if(!Globals.RUN_SERVER){ - initCommonWorldData(Globals.RUN_SERVER); - } - //initialize the "real" objects simulation - initMicroSimulation(); - //init client terrain manager - initClientTerrainManager(); - //initialize the cell manager (client) - initDrawCellManager(); - //initialize the basic graphical entities of the world (skybox, camera) - initWorldBaseGraphicalEntities(); - //init arena specific stuff (ie different skybox colors) - if(!Globals.RUN_SERVER){ - initArenaGraphicalEntities(); - } - //sets micro and macro sims to ready if they exist - if(!Globals.RUN_SERVER){ - setSimulationsToReady(); - } - //hide cursor - Globals.controlHandler.hideMouse(); - //make loading window disappear - loadingWindow.setVisible(false); - //recapture screen - Globals.controlHandler.setShouldRecapture(true); - //set rendering flags to main game mode - Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true; - Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = true; - Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = true; - Globals.RENDER_FLAG_RENDER_UI = true; - Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false; - Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false; - LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game"); - //set controls state - Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.MAIN_GAME); - break; - - - //intended to act like you went through the steps of setting up a vanilla settings SP world - case LOAD_DEBUG_RANDOM_SP_WORLD: { - //show loading - WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), false); - WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); - loadingWindow.setVisible(true); - - Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,0.0f,0); - if(!SaveUtils.getSaves().contains("random_sp_world")){ - // - //the juicy server GENERATION part - // - //init save structure - SaveUtils.createOrOverwriteSave("random_sp_world"); - //create terrain - Globals.serverTerrainManager.generate(); - Globals.serverTerrainManager.save(SaveUtils.deriveSaveDirectoryPath("random_sp_world")); - //create world.json - Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); - FileUtils.serializeObjectToSavePath("random_sp_world", "./world.json", Globals.serverWorldData); - } - //load just-created save - SaveUtils.loadSave("random_sp_world"); - //start initializing game datastructures - Globals.dataCellManager = new DataCellManager(Globals.serverWorldData); - //initialize the "virtual" objects simulation - initMacroSimulation(); - - - LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT); - //init the data of the world - initDataCellManager(); - //init authentication - initAuthenticationManager(); - //initialize the local connection - Globals.clientUsername = "testuser"; - Globals.clientPassword = AuthenticationManager.getHashedString("testpass"); - initLocalConnection(); - //initialize the "real" objects simulation - initMicroSimulation(); - //collision engine - initCommonWorldData(Globals.RUN_SERVER); - //init draw cell manager - initDrawCellManager(); - //init game specific stuff (ie different skybox colors) - initGameGraphicalEntities(); - //set simulations to ready if they exist - setSimulationsToReady(); - //log - LoggerInterface.loggerEngine.INFO("[Server]Finished loading main world"); - - //the less juicy client setup part - while(Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces().size() == 0){ - try { - TimeUnit.MILLISECONDS.sleep(5); - } catch (InterruptedException ex) {} - } - - - spawnLocalPlayerTestEntity(); - - initWorldBaseGraphicalEntities(); - - // SeekTown.attachToCreature(Globals.playerEntity); - - //hide cursor - Globals.controlHandler.hideMouse(); - //make loading window disappear - loadingWindow.setVisible(false); - //recapture screen - Globals.controlHandler.setShouldRecapture(true); - //set rendering flags to main game mode - Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true; - Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = true; - Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = true; - Globals.RENDER_FLAG_RENDER_UI = true; - Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false; - Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false; - LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game"); - //set controls state - Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.MAIN_GAME); - - } break; - - - - - - - - } - lock.release(); - } - - - public boolean isDone(){ - boolean rVal = lock.tryAcquire(); - if(rVal == true){ - lock.release(); - } - return rVal; - } - - - - static void initServerGameTerrainManager(){ - - /* - Actually initialize the terrain manager - */ - float randomDampener = 0.0f; //0.25f; - Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,randomDampener,0); - if(Globals.RUN_SERVER){ - if(Globals.userSettings.gameplayGenerateWorld()){ - Globals.serverTerrainManager.generate(); - Globals.serverTerrainManager.save("./terrain.json"); - } else { - SaveUtils.loadSave(Globals.currentSaveName); - } - } - - /* - Set spawn point - */ - int playerStartX = 0; - int playerStartY = 0; - int discreteSize = Globals.serverTerrainManager.getWorldDiscreteSize(); - int chunkSize = Globals.serverTerrainManager.getChunkWidth(); - boolean found = false; - for(int x = 0; x < discreteSize; x++){ - for(int y = 0; y < discreteSize; y++){ - if(Globals.serverTerrainManager.getDiscreteValue(x, y)>1800){ - playerStartX = x; - playerStartY = y; - found = true; - } - if(found){ - break; - } - } - if(found){ - break; - } - } - -// Globals.spawnPoint = new Vector3f(playerStartX * chunkSize, Globals.serverTerrainManager.getHeightAtPosition(playerStartX * chunkSize,playerStartY * chunkSize), playerStartY * chunkSize); - - - - } - - static void initServerArenaTerrainManager(){ - Globals.serverTerrainManager = ServerTerrainManager.constructArenaTerrainManager(); - } - - static void initClientTerrainManager(){ - Globals.clientTerrainManager = new ClientTerrainManager(Globals.clientWorldData); - } - - static void initServerArenaWorldData(){ - Globals.serverWorldData = ServerWorldData.createArenaWorld(); - Globals.spawnPoint = new Vector3d(1,0.1,1); -// Globals.serverTerrainManager.getChunk(0, 0).addModification(new TerrainModification(0,0,5,5,5)); - } - - static void initServerGameWorldData(){ - Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); - } - - static void initCommonWorldData(boolean FLAG_INIT_SERVER){ - if(Globals.commonWorldData == null){ - if(FLAG_INIT_SERVER){ - Globals.commonWorldData = new CommonWorldData(Globals.serverWorldData, Globals.serverTerrainManager); - if(Globals.macroSimulation != null){ - Town startTown = Globals.macroData.getTowns().get(0); - Vector2i firstPos = startTown.getPositions().get(0); - // double startX = firstPos.x * Globals.serverTerrainManager.getChunkWidth(); - // double startZ = firstPos.y * Globals.serverTerrainManager.getChunkWidth(); - double startX = Globals.commonWorldData.convertWorldToReal(firstPos.x); - double startZ = Globals.commonWorldData.convertWorldToReal(firstPos.y); - Globals.spawnPoint.set((float)startX,(float)Globals.commonWorldData.getElevationAtPoint(new Vector3d(startX,0,startZ)),(float)startZ); - } - } else { - //basically wait for the client to receive the world metadata - while(!Globals.clientConnection.getClientProtocol().hasReceivedWorld()){ - try { - TimeUnit.MILLISECONDS.sleep(5); - } catch (InterruptedException ex) { - } - } - //then create common world data - Globals.commonWorldData = new CommonWorldData(Globals.clientWorldData, Globals.clientTerrainManager); - } - } - } - - static void initDataCellManager(){ - Globals.dataCellManager = new DataCellManager(Globals.serverWorldData); - Globals.dataCellManager.init(); - } - - - - static void initServerThread(){ - //start server networking - if(Globals.RUN_SERVER){ - Globals.server = new Server(NetUtils.getPort()); - Globals.serverThread = new Thread(Globals.server); - Globals.serverThread.start(); - } - } - - static void initAuthenticationManager(){ - if(Globals.RUN_SERVER){ - Globals.authenticationManager = new AuthenticationManager(); - } - } - - - - static void initClientThread(){ - //start client networking - Thread clientThread = null; - if(Globals.RUN_CLIENT){ - Globals.clientConnection = new ClientNetworking(NetUtils.getAddress(),NetUtils.getPort()); - clientThread = new Thread(Globals.clientConnection); - clientThread.start(); - } - } - - static void initLocalConnection(){ - Globals.server = new Server(NetUtils.getPort()); - try { - //client -> server pipe - PipedInputStream clientInput = new PipedInputStream(); - PipedOutputStream serverOutput = new PipedOutputStream(clientInput); - //server -> client pipe - PipedInputStream serverInput = new PipedInputStream(); - PipedOutputStream clientOutput = new PipedOutputStream(serverInput); - //start server communication thread - Globals.server.addLocalPlayer(serverInput, serverOutput); - //start client communication thread - Globals.clientConnection = new ClientNetworking(clientInput,clientOutput); - Thread clientThread = null; - clientThread = new Thread(Globals.clientConnection); - clientThread.start(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - - static void initDrawCellManager(){ - //if it hasn't already been initialized, create draw cell manager - if(Globals.drawCellManager == null){ - Globals.drawCellManager = new DrawCellManager( - Globals.commonWorldData, - Globals.clientTerrainManager, - Globals.clientPlayerData.getWorldPositionX(), - Globals.clientPlayerData.getWorldPositionY() - ); - } - if(Globals.RUN_CLIENT == true) { - //set our draw cell manager to actually generate drawable chunks - Globals.drawCellManager.setGenerateDrawables(true); - } - //wait for all the terrain data to arrive - if(Globals.RUN_CLIENT){ - while(Globals.drawCellManager.containsInvalidCell()){ - // Globals.drawCellManager.updateInvalidCell(); - try { - TimeUnit.MILLISECONDS.sleep(10); - } catch (InterruptedException ex) { - } - // System.out.println("invalid cell"); - } - - while(Globals.drawCellManager.containsUndrawableCell()){ - // Globals.drawCellManager.makeCellDrawable(); - try { - TimeUnit.MILLISECONDS.sleep(10); - } catch (InterruptedException ex) { - } - // System.out.println("undrawable"); - } - - while(Globals.drawCellManager.containsPhysicsNeedingCell()){ - try { - TimeUnit.MILLISECONDS.sleep(10); - } catch (InterruptedException ex) { - } - } - } - // System.out.println("Draw Cell Manager ready"); - } - - - static void initGameGraphicalEntities(){ - - - float skyR = 100; - float skyG = 150; - float skyB = 200; - - float groundR = 50; - float groundG = 100; - float groundB = 150; - - Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); - Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); - Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); - Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); - Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); - Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); - Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); - Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); - - } - - - static void initArenaGraphicalEntities(){ - - float skyR = 150; - float skyG = 200; - float skyB = 250; - - float groundR = 20; - float groundG = 20; - float groundB = 20; - - Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); - Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); - Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); - Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); - Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); - Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); - Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); - Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); - - //starry sky true skybox - Entity skybox = EntityUtils.spawnDrawableEntity("Models/skyboxSphere.fbx"); - EntityUtils.getRotation(skybox).rotateX((float)(-Math.PI/2.0f)); - EntityUtils.getScale(skybox).mul(2000.0f); - Globals.assetManager.queueOverrideMeshShader("Models/skyboxSphere.fbx", "Sphere", "Shaders/skysphere/skysphere.vs", "Shaders/skysphere/skysphere.fs"); - - //cloud ring pseudo skybox - Entity cloudRing = EntityUtils.spawnDrawableEntity("Models/cloudRing.fbx"); - EntityUtils.getRotation(cloudRing).rotateX((float)(-Math.PI/2.0f)); - EntityUtils.getScale(cloudRing).mul(1000.0f); - Globals.entityManager.registerBehaviorTree(new ApplyRotationTree(cloudRing,new Quaternionf().rotationZ(0.0001f))); - Globals.assetManager.queueOverrideMeshShader("Models/cloudRing.fbx", "Sphere", "Shaders/skysphere/skysphere.vs", "Shaders/skysphere/skysphere.fs"); - - } - - - static void initWorldBaseGraphicalEntities(){ - /* - - Skybox - - */ - // Model skyboxModel = Globals.assetManager.fetchModel(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC); - // Globals.skybox = EntityUtils.spawnDrawableEntity(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC); - - - /* - - Player Camera - - */ - Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); - // Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityAirplaneTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); - - - - /* - Targeting crosshair - */ - Crosshair.initCrossHairEntity(); - - } - - static void initMacroSimulation(){ - Globals.macroData = MacroData.generateWorld(0); -// Globals.macroData.describeWorld(); - Globals.macroSimulation = new MacroSimulation(); - Globals.macroSimulation.simulate(); -// Town startTown = Globals.macroData.getTowns().get(0); -// Vector2i firstPos = startTown.getPositions().get(0); -// double startX = firstPos.x * Globals.serverTerrainManager.getChunkWidth(); -// double startZ = firstPos.y * Globals.serverTerrainManager.getChunkWidth(); -// Globals.spawnPoint.set((float)startX,(float)Globals.commonWorldData.getElevationAtPoint(new Vector3d(startX,0,startZ)),(float)startZ); -// Globals.macroSimulation.setReady(true); - } - - - static void initMicroSimulation(){ - if(Globals.microSimulation == null){ - Globals.microSimulation = new MicroSimulation(); - } - } - - static void setSimulationsToReady(){ - Globals.microSimulation.setReady(true); - if(Globals.macroSimulation != null){ - Globals.macroSimulation.setReady(true); - } - } - - static void creatingRandomEntities(){ -// String unitCubeModelPath = Globals.assetManager.registerModel(ModelUtils.createUnitCube()); -// Entity unitCube = EntityUtils.spawnDrawableEntity(unitCubeModelPath); -// EntityUtils.getEntityPosition(unitCube).set(10,2,10); - -// String goundPlaneModelPath = "Models/groundplanemassiveuv.fbx"; -// Entity groundPlane = EntityUtils.spawnDrawableEntity(goundPlaneModelPath); -// EntityUtils.getEntityPosition(groundPlane).set(10f,2f,10f); -// EntityUtils.getEntityRotation(groundPlane).rotateAxis((float)Math.PI/2, new Vector3f(1,0,0)); -// EntityUtils.getEntityScale(groundPlane).set(5); - -// String unitsphereModelPath = "Models/unitsphere.fbx"; -// Entity unitsphere = EntityUtils.spawnDrawableEntity(unitsphereModelPath); -// EntityUtils.getEntityPosition(unitsphere).set(10f,2f,10f); -// EntityUtils.getEntityScale(unitsphere).set(1); - -// String smallCubePath = "Models/SmallCube.fbx"; -// Entity originCube = EntityUtils.spawnDrawableEntity(smallCubePath); -// EntityUtils.getEntityPosition(originCube).set(0, 0, 0); -// -// originCube = EntityUtils.spawnDrawableEntity(smallCubePath); -// EntityUtils.getEntityPosition(originCube).set(1, 0, 0); -// -// originCube = EntityUtils.spawnDrawableEntity(smallCubePath); -// EntityUtils.getEntityPosition(originCube).set(0, 0, 1); - -// Entity font = FontUtils.makeFont(7, 1); -// EntityUtils.getEntityPosition(font).set(new Vector3f(0.2f,0.2f,0.0f)); - -// for(int i = 0; i < 10; i++){ -// Random rand = new Random(); -// Entity creature = CreatureUtils.spawnBasicCreature(0, 0.01f, 0.01f); -// EntityUtils.getEntityPosition(creature).set(rand.nextFloat() * 10, rand.nextFloat() * 10, rand.nextFloat() * 10); -// EntityUtils.getEntityScale(creature).set(0.01f); -// } - - //trees \:D/ -// for(int i = 0; i < 10; i++){ -// Random rand = new Random(); -// String treePath = "Models/tree1.fbx"; -// Entity tree = EntityUtils.spawnDrawableEntity(treePath); -// EntityUtils.getPosition(tree).set(rand.nextFloat() * 150 + 10, 0, rand.nextFloat() * 150 + 10); -//// EntityUtils.getEntityRotation(tree).rotateAxis((float)-Math.PI/2.0f, new Vector3f(1,0,0)); -// } - -// for(int i = 0; i < 250; i++){ -// Random rand = new Random(); -// String treePath = "Models/falloak1.fbx"; -// Entity tree = EntityUtils.spawnDrawableEntity(treePath); -// EntityUtils.getPosition(tree).set(rand.nextFloat() * 105 + 1, 0, rand.nextFloat() * 105 + 1); -// EntityUtils.getRotation(tree).rotateLocalX(-(float)Math.PI/2.0f).rotateZ(rand.nextFloat()); -// // EntityUtils.getEntityRotation(tree).rotateAxis((float)-Math.PI/2.0f, new Vector3f(1,0,0)); -// } - -// Random rand = new Random(); -// for(int i = 0; i < 1000; i++){ -// String wheatPath = "Models/wheat2.fbx"; -// Entity wheatStalk = EntityUtils.spawnDrawableEntity(wheatPath); -// EntityUtils.getPosition(wheatStalk).set(rand.nextFloat() * 20, 0, rand.nextFloat() * 20); -// EntityUtils.getRotation(wheatStalk).rotateLocalX(-(float)Math.PI/2.0f); -// EntityUtils.getScale(wheatStalk).set(1, 1, 2); -// } - -// String buildingPath = "Models/building1.fbx"; -// Entity building = EntityUtils.spawnDrawableEntity(buildingPath); -// EntityUtils.getPosition(building).set(5,1.2f,5); -// EntityUtils.getScale(building).set(0.5f); -// EntityUtils.getRotation(building).rotateLocalY((float)(Math.PI)); -// ActorUtils.applyBlenderTransformer(building); - - //spawn evil goblin - // Entity goblin = CreatureUtils.spawnBasicCreature("goblin"); - // CollisionObjUtils.positionCharacter(goblin, new Vector3f(4, 0, 4)); - // EntityUtils.getScale(goblin).set(0.005f); - // //give evil goblin sword - // Entity goblinSword = ItemUtils.spawnBasicItem("Katana"); - // AttachUtils.attachEntityToEntityAtBone(goblin, goblinSword, "Bone.031"); - // // attach ai to evil goblin - // MindlessAttacker.attachToCreature(goblin); - // OpportunisticAttacker.attachToCreature(goblin); - - //sword - // Entity sword = ItemUtils.spawnBasicItem("Katana"); - // EntityUtils.initiallyPositionEntity(sword, new Vector3d(1,0.4f,2)); - // EntityUtils.getRotation(sword).set(new Quaternionf().rotationY((float)(Math.PI/2.0))); - - //floating island 1 - // Entity island1 = ObjectUtils.spawnBasicObject("floatingisland1"); - // EntityUtils.getRotation(island1).set(new Quaternionf().rotationX(-(float)(Math.PI/2.0))); - // EntityUtils.getScale(island1).set(0.3f); - // EntityUtils.initiallyPositionEntity(island1, new Vector3d(5,0.5,5)); - - //work on ez volumetrics shader - // Entity myCube = EntityUtils.spawnDrawableEntity("Models/unitcube.fbx"); - // EntityUtils.getActor(myCube).maskShader("Cube", "Shaders/clouds1/clouds1.vs", "Shaders/clouds1/clouds1.fs"); - // Globals.assetManager.addShaderToQueue("Shaders/clouds1/clouds1.vs", "Shaders/clouds1/clouds1.fs"); - // myCube.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true); - // EntityUtils.getPosition(myCube).set(3,1,3); - - //work on smoke shader - // Entity myCube = EntityUtils.spawnDrawableEntity("Models/unitcube.fbx"); - // EntityUtils.getActor(myCube).maskShader("Cube", "Shaders/smoke1/smoke1.vs", "Shaders/smoke1/smoke1.fs"); - // Globals.assetManager.addShaderToQueue("Shaders/smoke1/smoke1.vs", "Shaders/smoke1/smoke1.fs"); - // myCube.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true); - // EntityUtils.getPosition(myCube).set(3,1,3); - - // SceneLoader loader = new SceneLoader(); - // loader.serverInstantiateSceneFile("Scenes/testscene1/testscene1.json"); - - - // Entity chunk = TerrainChunk.createTerrainChunkEntity(); - - - Random rand = new Random(); - for(int i = 0; i < 100; i++){ - Entity leaves = EntityUtils.spawnDrawableEntity(AssetDataStrings.LEAVES_MODEL); - float rad = rand.nextFloat(); - float angle = (float)(rand.nextFloat() * 2.0 * Math.PI); - Vector3d position = new Vector3d(Math.cos(angle) * rad + 4,1 + (rand.nextFloat() - 0.5),Math.sin(angle) * rad + 4); - Quaternionf rotation = new Quaternionf(rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat()).normalize(); - System.out.println(position); - EntityUtils.repositionEntity(leaves, position); - EntityUtils.getPosition(leaves).set(position); - EntityUtils.getRotation(leaves).slerp(rotation, 0.3f); - leaves.removeData(EntityDataStrings.DRAW_SOLID_PASS); - leaves.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true); - } - - // Globals.entityManager.registerBehaviorTree(new BehaviorTree() { - // int i = 0; - // public void simulate(){ - // if(i < 100){ - // i++; - // CollisionObjUtils.getCollidable(sword).addImpulse(new Impulse(new Vector3d(0,0,1), new Vector3d(-1,0,0), 0.001, Collidable.TYPE_CREATURE)); - // EntityUtils.getPosition(sword).set(1,0.2f,2); - // } - // }}); - - // Globals.entityManager.registerBehaviorTree(new BehaviorTree() { - // int i = 0; - // public void simulate(){ - // if(i < 10000){ - // i++; - // if(i % 100 == 0){ - // Entity sword = ItemUtils.spawnBasicItem("Katana"); - // EntityUtils.getPosition(sword).set(new Vector3f(1,1.4f,2)); - // EntityUtils.getRotation(sword).set(new Quaternionf().rotationY((float)(Math.PI/2.0))); - // } - // } - // }}); - - - - // DebugVisualizerUtils.spawnVectorVisualizer(new Vector3d(0,0,0), new Vector3d(-1,-1,-1)); - - // Entity shorts = ItemUtils.spawnBasicItem("boots1"); - // EntityUtils.getPosition(shorts).set(new Vector3f(2,0.1f,2)); - // // Entity hair = ItemUtils.spawnBasicItem("hairshort1"); - // // EntityUtils.getPosition(hair).set(new Vector3f(2,0.1f,1)); - - - // Entity bow = ItemUtils.spawnBasicItem("bow1"); - // EntityUtils.getPosition(bow).set(new Vector3f(2,0.1f,1)); - - //crate - // Entity crate = EntityUtils.spawnDrawableEntity("Models/crate2.fbx"); - // EntityUtils.getPosition(crate).set(5,0.5,5); - // EntityUtils.getScale(crate).set(new Vector3f(0.5f)); - - // //center flame - // Entity fire = ParticleUtils.spawnStaticBillboardParticle(); - // EntityUtils.getPosition(fire).set(new Vector3f(1,0.2f,1)); - // EntityUtils.getScale(fire).set(0.6f); - // Actor fireActor = EntityUtils.getActor(fire); - // fireActor.maskShader("particleBillboard", "Shaders/flame1/flame.vs", "Shaders/flame1/flame.fs"); - // Globals.assetManager.addShaderToQueue("Shaders/flame1/flame.vs", "Shaders/flame1/flame.fs"); - - // // //campfire - // Entity campfire = EntityUtils.spawnDrawableEntity("Models/campfire1.fbx"); - // EntityUtils.getPosition(campfire).set(1,0,1); - // EntityUtils.getRotation(campfire).rotationX(-(float)Math.PI/2.0f); - // campfire.putData(EntityDataStrings.DRAW_OUTLINE, true); - - // //flame - // Entity cube = EntityUtils.spawnDrawableEntity("Models/flame1.fbx"); - // //shader mask - // EntityUtils.getActor(cube).maskShader("Sphere", "Shaders/flame2/flame.vs", "Shaders/flame2/flame.fs"); - // Globals.assetManager.addShaderToQueue("Shaders/flame2/flame.vs", "Shaders/flame2/flame.fs"); - // EntityUtils.getScale(cube).set(0.8f); - // EntityUtils.getPosition(cube).set(1,0.08f,1); - // EntityUtils.getRotation(cube).rotationX(-(float)Math.PI/2.0f); - // //texture mask - // EntityUtils.getActor(cube).addTextureMask(RenderUtils.generateVolumetricTextureMask("Sphere")); - // //set draw volumetric - // cube.putData(EntityDataStrings.DRAW_VOLUMETRIC, true); - - - // Globals.assetManager.addShaderToQueue("Shaders/grass1/grass1.vs", "Shaders/grass1/grass1.gs", "Shaders/grass1/grass1.fs"); - // Entity grass = EntityUtils.spawnDrawableEntity("Models/grass1.fbx"); - // //shader mask - // EntityUtils.getActor(grass).maskShader("Cube", "Shaders/grass1/grass1.vs", "Shaders/grass1/grass1.gs", "Shaders/grass1/grass1.fs"); - // EntityUtils.getPosition(grass).set(3,0,1); - - // queue grass shader - // Globals.assetManager.addShaderToQueue("Shaders/grass1/grass1.vs", "Shaders/grass1/grass1.gs", "Shaders/grass1/grass1.fs"); - // for(int x = 0; x < 10; x++){ - // for(int y = 0; y < 10; y++){ - // Entity grass = EntityUtils.spawnDrawableEntity("Models/grass1.fbx"); - // //shader mask - // EntityUtils.getActor(grass).maskShader("Cube", "Shaders/grass1/grass1.vs", "Shaders/grass1/grass1.gs", "Shaders/grass1/grass1.fs"); - // EntityUtils.getPosition(grass).set(3 + x / 5.0f,0.0,1 + y / 5.0f); - // } - // } - - - // //water cube - // Entity water = EntityUtils.spawnDrawableEntity("Models/watercube1.fbx"); - // EntityUtils.getActor(water).maskShader("Cube", "Shaders/water1/water.vs", "Shaders/water1/water.fs"); - // Globals.assetManager.addShaderToQueue("Shaders/water1/water.vs", "Shaders/water1/water.fs"); - // // EntityUtils.getPosition(water).set(5,0.51,5); - // // EntityUtils.getRotation(water).rotationX((float)Math.PI/4.0f); - // EntityUtils.getPosition(water).set(5,-0.1,5); - // EntityUtils.getScale(water).set(1,1,1); - // //texture mask - // EntityUtils.getActor(water).addTextureMask(RenderUtils.generateVolumetricTextureMask("Cube")); - // //set draw volumetric - // water.putData(EntityDataStrings.DRAW_VOLUMETRIC, true); - // water.removeData(EntityDataStrings.DRAW_SOLID_PASS); - // water.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true); - - - - // //shrine 2 - // Entity shrine = EntityUtils.spawnDrawableEntity("Models/shrine2.fbx"); - // EntityUtils.getPosition(shrine).set(15,0,15); - // EntityUtils.getRotation(shrine).rotationX((float)-Math.PI/2.0f); - // shrine.putData(EntityDataStrings.DRAW_OUTLINE, true); - - -// goblin = CreatureUtils.spawnBasicCreature("Goblin"); -// CollisionObjUtils.positionCharacter(goblin, new Vector3f(3, 0, 4)); -// EntityUtils.getScale(goblin).set(0.005f); -// -// goblin = CreatureUtils.spawnBasicCreature("Goblin"); -// CollisionObjUtils.positionCharacter(goblin, new Vector3f(4, 0, 3)); -// EntityUtils.getScale(goblin).set(0.005f); -// -// goblin = CreatureUtils.spawnBasicCreature("Goblin"); -// CollisionObjUtils.positionCharacter(goblin, new Vector3f(3, 0, 3)); -// EntityUtils.getScale(goblin).set(0.005f); - -// UnitUtils.spawnTextGoblin(10, 0, 10); - -// StructureUtils.spawnBasicStructure("building1", new Vector3f(5,2.4f,5), new Quaternionf()); - -// Entity bow = ItemUtils.spawnBasicItem("Bow"); -// EntityUtils.getPosition(bow).set(1, 1, 2); - -// NavMeshPathfinder.navigatePointToPointInMesh(G*lobals.navMeshManager.getMeshes().get(0), new Vector3d(10,0,5), new Vector3d(5,0,10)); - -// NavMesh mesh = new NavMesh(); -// NavCube cube = new NavCube(5,0,0,10,5,5); -// mesh.addNode(cube); -// Globals.navMeshManager.addMesh(mesh); - -// Entity fallOak = FoliageUtils.spawnBasicFoliage("FallOak1"); -// EntityUtils.getPosition(fallOak).set(1,0,3); -// -// Entity spark = ParticleUtils.spawnBillboardParticle("Textures/animetree1leaves1.png", 150000, new Vector3f(0,0,0), 0, 0); -// EntityUtils.getPosition(spark).set(new Vector3f(3,3,3)); -// EntityUtils.getScale(spark).mul(1f); - -// System.out.println(Globals.drawCellManager.) - -// Entity deer = CreatureUtils.spawnBasicCreature("Deer"); -// EntityUtils.getPosition(deer).set(5, 0.25f, 3); - - -// Model deerModel = Globals.assetManager.fetchModel("Models/deer1.fbx"); -// deerModel.describeHighLevel(); - - -// CollisionObjUtils.positionCharacter(fallOak, new Vector3f(1, 0, 3)); -// -// -// Entity testHomie = CreatureUtils.spawnBasicCreature("Human"); -// EntityUtils.getScale(testHomie).set(0.005f); -// CreatureUtils.positionCharacter(testHomie, new Vector3f(10,1,10)); -// -// Entity sword = ItemUtils.spawnBasicItem("Katana"); -// AttachUtils.attachEntityToEntityAtBone(testHomie, sword, "Bone.020"); - - -// CollisionObjUtils.spawnCollisionPlane(new Vector3f(1,1,1), new Vector3f(8,2,10), new Quaternionf()); // .rotateLocalX(0.75f) - -// CollisionObjUtils.spawnCollisionCube(new Vector3f(1,1,1), new Vector3f(10,1,10), new Quaternionf()); - -// CreatureUtils.positionCharacter(Globals.playerCharacter, new Vector3f(10,3,10)); - -// StructureUtils.spawnBasicStructure("building1", new Vector3f(10,2.4f,15), new Quaternionf().rotateLocalY((float)Math.PI)); - } - - /** - * Spawns the character, and sets server side connection player object values to the appropriate chunk - */ - static void spawnLocalPlayerTestEntity(){ - // - //Create entity - // - //send default template back - String race = Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces().get(0); - CreatureType type = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(race); - CreatureTemplate template = new CreatureTemplate(race); - for(VisualAttribute attribute : type.getVisualAttributes()){ - if(attribute.getType().equals(VisualAttribute.TYPE_BONE)){ - float min = attribute.getMinValue(); - float max = attribute.getMaxValue(); - float defaultValue = min + (max - min)/2.0f; - //add attribute to creature template - template.putValue(attribute.getAttributeId(), defaultValue); - } else if(attribute.getType().equals(VisualAttribute.TYPE_REMESH)){ - template.putValue(attribute.getAttributeId(), attribute.getVariants().get(0).getId()); - } - } - //spawn entity - Entity newPlayerEntity = CreatureUtils.spawnBasicCreature(template.getCreatureType(),template); - Globals.playerEntity = newPlayerEntity; - - //set player world-space coordinates - Player playerObject = Globals.playerManager.getPlayerFromId(0); - playerObject.setWorldX(Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x)); - playerObject.setWorldY(Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z)); - //set client entity data - Globals.clientPlayerData.setWorldPosition(playerObject.getWorldX(), playerObject.getWorldY()); - //initially position entity - EntityUtils.initiallyPositionEntity(newPlayerEntity, new Vector3d(Globals.spawnPoint.x + 1,Globals.spawnPoint.y + 5,Globals.spawnPoint.z + 1)); - //add entity to correct cells - Globals.dataCellManager.addPlayerToGroundCells(playerObject); - Globals.dataCellManager.movePlayerGroundCells(playerObject, Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x), Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z)); - } - - -} diff --git a/src/main/java/electrosphere/engine/Main.java b/src/main/java/electrosphere/engine/Main.java index 0c931f94..250103ad 100644 --- a/src/main/java/electrosphere/engine/Main.java +++ b/src/main/java/electrosphere/engine/Main.java @@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit; import electrosphere.audio.AudioEngine; import electrosphere.controls.ControlHandler; import electrosphere.engine.cli.CLIParser; +import electrosphere.engine.loadingthreads.LoadingThread; import electrosphere.game.client.ClientFunctions; import electrosphere.game.config.UserSettings; import electrosphere.logger.LoggerInterface; @@ -189,10 +190,17 @@ public class Main { // RenderUtils.recaptureScreen(); } + /** + * Runs the main loop indefinitely. Blocks the thread this is called in. + */ public static void mainLoop(){ mainLoop(0); } + /** + * Runs the main loop for a specified number of frames. + * @param maxFrames The number of frames to run for. If 0, will run indefinitely. + */ public static void mainLoop(long maxFrames){ //main loop @@ -246,15 +254,25 @@ public class Main { /// /// C L I E N T S I M U L A T I O N S T U F F /// - if(Globals.RUN_CLIENT && framestep > 0){ + if(Globals.clientSimulation != null && Globals.clientSimulation.isReady() && framestep > 0){ ClientFunctions.runBeforeSimulationFunctions(); } - if(Globals.microSimulation != null && Globals.microSimulation.isReady() && framestep > 0){ - Globals.microSimulation.simulate(); + if(Globals.clientSimulation != null && Globals.clientSimulation.isLoadingTerrain() && framestep > 0){ + ClientFunctions.loadTerrain(); } - if(Globals.RUN_CLIENT && framestep > 0){ + if(Globals.clientSimulation != null && Globals.clientSimulation.isReady() && framestep > 0){ + Globals.clientSimulation.simulate(); + } + if(Globals.clientSimulation != null && Globals.clientSimulation.isReady() && framestep > 0){ ClientFunctions.runClientFunctions(); } + + /// + /// S E R V E R M I C R O S I M U L A T I O N + /// + if(Globals.realmManager != null){ + Globals.realmManager.simulate(); + } /// /// M A C R O S I M U L A T I O N S T U F F diff --git a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java index c617a918..4293aeba 100644 --- a/src/main/java/electrosphere/engine/assetmanager/AssetManager.java +++ b/src/main/java/electrosphere/engine/assetmanager/AssetManager.java @@ -9,6 +9,7 @@ import electrosphere.renderer.ShaderProgram; import electrosphere.renderer.actor.ActorShaderMask; import electrosphere.renderer.loading.ModelLoader; import electrosphere.renderer.texture.Texture; +import electrosphere.server.poseactor.PoseModel; import java.util.LinkedList; import java.util.List; @@ -40,6 +41,9 @@ public class AssetManager { Map physicsMeshesLoadedIntoMemory = new ConcurrentHashMap(); List physicsMeshesToLoad = new CopyOnWriteArrayList(); + + Map poseModelsLoadedIntoMemory = new ConcurrentHashMap(); + List poseModelsInQueue = new CopyOnWriteArrayList(); @@ -82,6 +86,11 @@ public class AssetManager { ); } } + for(String currentPath: poseModelsInQueue){ + poseModelsInQueue.remove(currentPath); + AIScene scene = ModelLoader.loadAIScene(currentPath); + poseModelsLoadedIntoMemory.put(currentPath, new PoseModel(currentPath, scene)); + } performMeshOverrides(); } @@ -178,6 +187,26 @@ public class AssetManager { + + + + // + //Pose Models + // + + public void addPoseModelPathToQueue(String path){ + if(!poseModelsInQueue.contains(path) && !poseModelsLoadedIntoMemory.containsKey(path)){ + poseModelsInQueue.add(path); + } + } + + public PoseModel fetchPoseModel(String path){ + PoseModel rVal = null; + if(poseModelsLoadedIntoMemory.containsKey(path)){ + rVal = poseModelsLoadedIntoMemory.get(path); + } + return rVal; + } diff --git a/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java new file mode 100644 index 00000000..0c77e063 --- /dev/null +++ b/src/main/java/electrosphere/engine/loadingthreads/ArenaLoading.java @@ -0,0 +1,376 @@ +package electrosphere.engine.loadingthreads; + +import java.util.Random; + +import org.joml.Quaternionf; +import org.joml.Vector3d; + +import electrosphere.engine.Globals; +import electrosphere.engine.assetmanager.AssetDataStrings; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.ServerEntityUtils; +import electrosphere.game.server.terrain.manager.ServerTerrainManager; +import electrosphere.game.server.world.ServerWorldData; +import electrosphere.logger.LoggerInterface; +import electrosphere.server.saves.SaveUtils; +import electrosphere.util.FileUtils; + +public class ArenaLoading { + + protected static void loadArenaGameServer(){ + //init server arena terrain manager separately + initServerArenaTerrainManager(); + //init the data of the world + initServerArenaWorldData(); + //init data cell manager + // LoadingUtils.initTerrainDataCellManager(); + //for testing purposes + FileUtils.recursivelyDelete("/Users/satellite/temp/saves/arena"); + //init database connection + SaveUtils.initSave("arena"); + //connect to database + SaveUtils.loadSave("arena"); + //init authentication + LoadingUtils.initAuthenticationManager(); + //initialize the server thread (server only) + LoadingUtils.initServerThread(); + //collision engine + LoadingUtils.initCommonWorldData(Globals.RUN_SERVER); + //init gridded datacell manager + LoadingUtils.initGriddedRealm(); + //initialize the "virtual" objects simulation + //not really relevant in arena mode +// initMacroSimulation(); + //initialize the "real" objects simulation + LoadingUtils.initMicroSimulation(); + //create arena entities + creatingRandomEntities(); + //set simulations to ready if they exist + LoadingUtils.setSimulationsToReady(); + LoggerInterface.loggerEngine.INFO("[Server]Finished loading arena world"); + } + + + + private static void initServerArenaTerrainManager(){ + Globals.serverTerrainManager = ServerTerrainManager.constructArenaTerrainManager(); + } + + private static void initServerArenaWorldData(){ + Globals.serverWorldData = ServerWorldData.createArenaWorld(); + Globals.spawnPoint = new Vector3d(1,0.1,1); +// Globals.serverTerrainManager.getChunk(0, 0).addModification(new TerrainModification(0,0,5,5,5)); + } + + + + + private static void creatingRandomEntities(){ + // String unitCubeModelPath = Globals.assetManager.registerModel(ModelUtils.createUnitCube()); + // Entity unitCube = EntityUtils.spawnDrawableEntity(unitCubeModelPath); + // EntityUtils.getEntityPosition(unitCube).set(10,2,10); + + // String goundPlaneModelPath = "Models/groundplanemassiveuv.fbx"; + // Entity groundPlane = EntityUtils.spawnDrawableEntity(goundPlaneModelPath); + // EntityUtils.getEntityPosition(groundPlane).set(10f,2f,10f); + // EntityUtils.getEntityRotation(groundPlane).rotateAxis((float)Math.PI/2, new Vector3f(1,0,0)); + // EntityUtils.getEntityScale(groundPlane).set(5); + + // String unitsphereModelPath = "Models/unitsphere.fbx"; + // Entity unitsphere = EntityUtils.spawnDrawableEntity(unitsphereModelPath); + // EntityUtils.getEntityPosition(unitsphere).set(10f,2f,10f); + // EntityUtils.getEntityScale(unitsphere).set(1); + + // String smallCubePath = "Models/SmallCube.fbx"; + // Entity originCube = EntityUtils.spawnDrawableEntity(smallCubePath); + // EntityUtils.getEntityPosition(originCube).set(0, 0, 0); + // + // originCube = EntityUtils.spawnDrawableEntity(smallCubePath); + // EntityUtils.getEntityPosition(originCube).set(1, 0, 0); + // + // originCube = EntityUtils.spawnDrawableEntity(smallCubePath); + // EntityUtils.getEntityPosition(originCube).set(0, 0, 1); + + // Entity font = FontUtils.makeFont(7, 1); + // EntityUtils.getEntityPosition(font).set(new Vector3f(0.2f,0.2f,0.0f)); + + // for(int i = 0; i < 10; i++){ + // Random rand = new Random(); + // Entity creature = CreatureUtils.spawnBasicCreature(0, 0.01f, 0.01f); + // EntityUtils.getEntityPosition(creature).set(rand.nextFloat() * 10, rand.nextFloat() * 10, rand.nextFloat() * 10); + // EntityUtils.getEntityScale(creature).set(0.01f); + // } + + //trees \:D/ + // for(int i = 0; i < 10; i++){ + // Random rand = new Random(); + // String treePath = "Models/tree1.fbx"; + // Entity tree = EntityUtils.spawnDrawableEntity(treePath); + // EntityUtils.getPosition(tree).set(rand.nextFloat() * 150 + 10, 0, rand.nextFloat() * 150 + 10); + //// EntityUtils.getEntityRotation(tree).rotateAxis((float)-Math.PI/2.0f, new Vector3f(1,0,0)); + // } + + // for(int i = 0; i < 250; i++){ + // Random rand = new Random(); + // String treePath = "Models/falloak1.fbx"; + // Entity tree = EntityUtils.spawnDrawableEntity(treePath); + // EntityUtils.getPosition(tree).set(rand.nextFloat() * 105 + 1, 0, rand.nextFloat() * 105 + 1); + // EntityUtils.getRotation(tree).rotateLocalX(-(float)Math.PI/2.0f).rotateZ(rand.nextFloat()); + // // EntityUtils.getEntityRotation(tree).rotateAxis((float)-Math.PI/2.0f, new Vector3f(1,0,0)); + // } + + // Random rand = new Random(); + // for(int i = 0; i < 1000; i++){ + // String wheatPath = "Models/wheat2.fbx"; + // Entity wheatStalk = EntityUtils.spawnDrawableEntity(wheatPath); + // EntityUtils.getPosition(wheatStalk).set(rand.nextFloat() * 20, 0, rand.nextFloat() * 20); + // EntityUtils.getRotation(wheatStalk).rotateLocalX(-(float)Math.PI/2.0f); + // EntityUtils.getScale(wheatStalk).set(1, 1, 2); + // } + + // String buildingPath = "Models/building1.fbx"; + // Entity building = EntityUtils.spawnDrawableEntity(buildingPath); + // EntityUtils.getPosition(building).set(5,1.2f,5); + // EntityUtils.getScale(building).set(0.5f); + // EntityUtils.getRotation(building).rotateLocalY((float)(Math.PI)); + // ActorUtils.applyBlenderTransformer(building); + + //spawn evil goblin + // Entity goblin = CreatureUtils.spawnBasicCreature("goblin"); + // CollisionObjUtils.positionCharacter(goblin, new Vector3f(4, 0, 4)); + // EntityUtils.getScale(goblin).set(0.005f); + // //give evil goblin sword + // Entity goblinSword = ItemUtils.spawnBasicItem("Katana"); + // AttachUtils.attachEntityToEntityAtBone(goblin, goblinSword, "Bone.031"); + // // attach ai to evil goblin + // MindlessAttacker.attachToCreature(goblin); + // OpportunisticAttacker.attachToCreature(goblin); + + //sword + // Entity sword = ItemUtils.spawnBasicItem("Katana"); + // EntityUtils.initiallyPositionEntity(sword, new Vector3d(1,0.4f,2)); + // EntityUtils.getRotation(sword).set(new Quaternionf().rotationY((float)(Math.PI/2.0))); + + //floating island 1 + // Entity island1 = ObjectUtils.spawnBasicObject("floatingisland1"); + // EntityUtils.getRotation(island1).set(new Quaternionf().rotationX(-(float)(Math.PI/2.0))); + // EntityUtils.getScale(island1).set(0.3f); + // EntityUtils.initiallyPositionEntity(island1, new Vector3d(5,0.5,5)); + + //work on ez volumetrics shader + // Entity myCube = EntityUtils.spawnDrawableEntity("Models/unitcube.fbx"); + // EntityUtils.getActor(myCube).maskShader("Cube", "Shaders/clouds1/clouds1.vs", "Shaders/clouds1/clouds1.fs"); + // Globals.assetManager.addShaderToQueue("Shaders/clouds1/clouds1.vs", "Shaders/clouds1/clouds1.fs"); + // myCube.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true); + // EntityUtils.getPosition(myCube).set(3,1,3); + + //work on smoke shader + // Entity myCube = EntityUtils.spawnDrawableEntity("Models/unitcube.fbx"); + // EntityUtils.getActor(myCube).maskShader("Cube", "Shaders/smoke1/smoke1.vs", "Shaders/smoke1/smoke1.fs"); + // Globals.assetManager.addShaderToQueue("Shaders/smoke1/smoke1.vs", "Shaders/smoke1/smoke1.fs"); + // myCube.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true); + // EntityUtils.getPosition(myCube).set(3,1,3); + + // SceneLoader loader = new SceneLoader(); + // loader.serverInstantiateSceneFile("Scenes/testscene1/testscene1.json"); + + + // Entity chunk = TerrainChunk.createTerrainChunkEntity(); + + + // Random rand = new Random(); + // for(int i = 0; i < 100; i++){ + // Entity leaves = EntityUtils.spawnDrawableEntity(AssetDataStrings.LEAVES_MODEL); + // float rad = rand.nextFloat(); + // float angle = (float)(rand.nextFloat() * 2.0 * Math.PI); + // Vector3d position = new Vector3d(Math.cos(angle) * rad + 4,1 + (rand.nextFloat() - 0.5),Math.sin(angle) * rad + 4); + // Quaternionf rotation = new Quaternionf(rand.nextFloat(), rand.nextFloat(), rand.nextFloat(), rand.nextFloat()).normalize(); + // ServerEntityUtils.repositionEntity(leaves, position); + // EntityUtils.getPosition(leaves).set(position); + // EntityUtils.getRotation(leaves).slerp(rotation, 0.3f); + // leaves.removeData(EntityDataStrings.DRAW_SOLID_PASS); + // leaves.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true); + // } + + // Globals.entityManager.registerBehaviorTree(new BehaviorTree() { + // int i = 0; + // public void simulate(){ + // if(i < 100){ + // i++; + // CollisionObjUtils.getCollidable(sword).addImpulse(new Impulse(new Vector3d(0,0,1), new Vector3d(-1,0,0), 0.001, Collidable.TYPE_CREATURE)); + // EntityUtils.getPosition(sword).set(1,0.2f,2); + // } + // }}); + + // Globals.entityManager.registerBehaviorTree(new BehaviorTree() { + // int i = 0; + // public void simulate(){ + // if(i < 10000){ + // i++; + // if(i % 100 == 0){ + // Entity sword = ItemUtils.spawnBasicItem("Katana"); + // EntityUtils.getPosition(sword).set(new Vector3f(1,1.4f,2)); + // EntityUtils.getRotation(sword).set(new Quaternionf().rotationY((float)(Math.PI/2.0))); + // } + // } + // }}); + + + + // DebugVisualizerUtils.spawnVectorVisualizer(new Vector3d(0,0,0), new Vector3d(-1,-1,-1)); + + // Entity shorts = ItemUtils.spawnBasicItem("boots1"); + // EntityUtils.getPosition(shorts).set(new Vector3f(2,0.1f,2)); + // // Entity hair = ItemUtils.spawnBasicItem("hairshort1"); + // // EntityUtils.getPosition(hair).set(new Vector3f(2,0.1f,1)); + + + // Entity bow = ItemUtils.spawnBasicItem("bow1"); + // EntityUtils.getPosition(bow).set(new Vector3f(2,0.1f,1)); + + //crate + // Entity crate = EntityUtils.spawnDrawableEntity("Models/crate2.fbx"); + // EntityUtils.getPosition(crate).set(5,0.5,5); + // EntityUtils.getScale(crate).set(new Vector3f(0.5f)); + + // //center flame + // Entity fire = ParticleUtils.spawnStaticBillboardParticle(); + // EntityUtils.getPosition(fire).set(new Vector3f(1,0.2f,1)); + // EntityUtils.getScale(fire).set(0.6f); + // Actor fireActor = EntityUtils.getActor(fire); + // fireActor.maskShader("particleBillboard", "Shaders/flame1/flame.vs", "Shaders/flame1/flame.fs"); + // Globals.assetManager.addShaderToQueue("Shaders/flame1/flame.vs", "Shaders/flame1/flame.fs"); + + // // //campfire + // Entity campfire = EntityUtils.spawnDrawableEntity("Models/campfire1.fbx"); + // EntityUtils.getPosition(campfire).set(1,0,1); + // EntityUtils.getRotation(campfire).rotationX(-(float)Math.PI/2.0f); + // campfire.putData(EntityDataStrings.DRAW_OUTLINE, true); + + // //flame + // Entity cube = EntityUtils.spawnDrawableEntity("Models/flame1.fbx"); + // //shader mask + // EntityUtils.getActor(cube).maskShader("Sphere", "Shaders/flame2/flame.vs", "Shaders/flame2/flame.fs"); + // Globals.assetManager.addShaderToQueue("Shaders/flame2/flame.vs", "Shaders/flame2/flame.fs"); + // EntityUtils.getScale(cube).set(0.8f); + // EntityUtils.getPosition(cube).set(1,0.08f,1); + // EntityUtils.getRotation(cube).rotationX(-(float)Math.PI/2.0f); + // //texture mask + // EntityUtils.getActor(cube).addTextureMask(RenderUtils.generateVolumetricTextureMask("Sphere")); + // //set draw volumetric + // cube.putData(EntityDataStrings.DRAW_VOLUMETRIC, true); + + + // Globals.assetManager.addShaderToQueue("Shaders/grass1/grass1.vs", "Shaders/grass1/grass1.gs", "Shaders/grass1/grass1.fs"); + // Entity grass = EntityUtils.spawnDrawableEntity("Models/grass1.fbx"); + // //shader mask + // EntityUtils.getActor(grass).maskShader("Cube", "Shaders/grass1/grass1.vs", "Shaders/grass1/grass1.gs", "Shaders/grass1/grass1.fs"); + // EntityUtils.getPosition(grass).set(3,0,1); + + // queue grass shader + // Globals.assetManager.addShaderToQueue("Shaders/grass1/grass1.vs", "Shaders/grass1/grass1.gs", "Shaders/grass1/grass1.fs"); + // for(int x = 0; x < 10; x++){ + // for(int y = 0; y < 10; y++){ + // Entity grass = EntityUtils.spawnDrawableEntity("Models/grass1.fbx"); + // //shader mask + // EntityUtils.getActor(grass).maskShader("Cube", "Shaders/grass1/grass1.vs", "Shaders/grass1/grass1.gs", "Shaders/grass1/grass1.fs"); + // EntityUtils.getPosition(grass).set(3 + x / 5.0f,0.0,1 + y / 5.0f); + // } + // } + + + // //water cube + // Entity water = EntityUtils.spawnDrawableEntity("Models/watercube1.fbx"); + // EntityUtils.getActor(water).maskShader("Cube", "Shaders/water1/water.vs", "Shaders/water1/water.fs"); + // Globals.assetManager.addShaderToQueue("Shaders/water1/water.vs", "Shaders/water1/water.fs"); + // // EntityUtils.getPosition(water).set(5,0.51,5); + // // EntityUtils.getRotation(water).rotationX((float)Math.PI/4.0f); + // EntityUtils.getPosition(water).set(5,-0.1,5); + // EntityUtils.getScale(water).set(1,1,1); + // //texture mask + // EntityUtils.getActor(water).addTextureMask(RenderUtils.generateVolumetricTextureMask("Cube")); + // //set draw volumetric + // water.putData(EntityDataStrings.DRAW_VOLUMETRIC, true); + // water.removeData(EntityDataStrings.DRAW_SOLID_PASS); + // water.putData(EntityDataStrings.DRAW_TRANSPARENT_PASS, true); + + + + // //shrine 2 + // Entity shrine = EntityUtils.spawnDrawableEntity("Models/shrine2.fbx"); + // EntityUtils.getPosition(shrine).set(15,0,15); + // EntityUtils.getRotation(shrine).rotationX((float)-Math.PI/2.0f); + // shrine.putData(EntityDataStrings.DRAW_OUTLINE, true); + + + // goblin = CreatureUtils.spawnBasicCreature("Goblin"); + // CollisionObjUtils.positionCharacter(goblin, new Vector3f(3, 0, 4)); + // EntityUtils.getScale(goblin).set(0.005f); + // + // goblin = CreatureUtils.spawnBasicCreature("Goblin"); + // CollisionObjUtils.positionCharacter(goblin, new Vector3f(4, 0, 3)); + // EntityUtils.getScale(goblin).set(0.005f); + // + // goblin = CreatureUtils.spawnBasicCreature("Goblin"); + // CollisionObjUtils.positionCharacter(goblin, new Vector3f(3, 0, 3)); + // EntityUtils.getScale(goblin).set(0.005f); + + // UnitUtils.spawnTextGoblin(10, 0, 10); + + // StructureUtils.spawnBasicStructure("building1", new Vector3f(5,2.4f,5), new Quaternionf()); + + // Entity bow = ItemUtils.spawnBasicItem("Bow"); + // EntityUtils.getPosition(bow).set(1, 1, 2); + + // NavMeshPathfinder.navigatePointToPointInMesh(G*lobals.navMeshManager.getMeshes().get(0), new Vector3d(10,0,5), new Vector3d(5,0,10)); + + // NavMesh mesh = new NavMesh(); + // NavCube cube = new NavCube(5,0,0,10,5,5); + // mesh.addNode(cube); + // Globals.navMeshManager.addMesh(mesh); + + // Entity fallOak = FoliageUtils.spawnBasicFoliage("FallOak1"); + // EntityUtils.getPosition(fallOak).set(1,0,3); + // + // Entity spark = ParticleUtils.spawnBillboardParticle("Textures/animetree1leaves1.png", 150000, new Vector3f(0,0,0), 0, 0); + // EntityUtils.getPosition(spark).set(new Vector3f(3,3,3)); + // EntityUtils.getScale(spark).mul(1f); + + // System.out.println(Globals.drawCellManager.) + + // Entity deer = CreatureUtils.spawnBasicCreature("Deer"); + // EntityUtils.getPosition(deer).set(5, 0.25f, 3); + + + // Model deerModel = Globals.assetManager.fetchModel("Models/deer1.fbx"); + // deerModel.describeHighLevel(); + + + // CollisionObjUtils.positionCharacter(fallOak, new Vector3f(1, 0, 3)); + // + // + // Entity testHomie = CreatureUtils.spawnBasicCreature("Human"); + // EntityUtils.getScale(testHomie).set(0.005f); + // CreatureUtils.positionCharacter(testHomie, new Vector3f(10,1,10)); + // + // Entity sword = ItemUtils.spawnBasicItem("Katana"); + // AttachUtils.attachEntityToEntityAtBone(testHomie, sword, "Bone.020"); + + + // CollisionObjUtils.spawnCollisionPlane(new Vector3f(1,1,1), new Vector3f(8,2,10), new Quaternionf()); // .rotateLocalX(0.75f) + + // CollisionObjUtils.spawnCollisionCube(new Vector3f(1,1,1), new Vector3f(10,1,10), new Quaternionf()); + + // CreatureUtils.positionCharacter(Globals.playerCharacter, new Vector3f(10,3,10)); + + // StructureUtils.spawnBasicStructure("building1", new Vector3f(10,2.4f,15), new Quaternionf().rotateLocalY((float)Math.PI)); + } + + + + + + +} diff --git a/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java new file mode 100644 index 00000000..a45f86d6 --- /dev/null +++ b/src/main/java/electrosphere/engine/loadingthreads/ClientLoading.java @@ -0,0 +1,253 @@ +package electrosphere.engine.loadingthreads; + +import java.util.concurrent.TimeUnit; + +import org.joml.Quaternionf; +import org.joml.Vector3f; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.movement.ApplyRotationTree; +import electrosphere.entity.types.camera.CameraEntityUtils; +import electrosphere.game.client.cells.DrawCellManager; +import electrosphere.game.client.targeting.crosshair.Crosshair; +import electrosphere.logger.LoggerInterface; +import electrosphere.menu.MenuGenerators; +import electrosphere.menu.MenuGeneratorsMultiplayer; +import electrosphere.menu.WindowStrings; +import electrosphere.menu.WindowUtils; +import electrosphere.net.NetUtils; +import electrosphere.net.client.ClientNetworking; +import electrosphere.renderer.ui.Window; +import electrosphere.client.culling.ClientEntityCullingManager; +import electrosphere.client.sim.ClientSimulation; +import electrosphere.controls.ControlHandler; + +public class ClientLoading { + + protected static void loadMainMenu(){ + Window loadingWindow = (Window)Globals.elementManager.getWindow(WindowStrings.WINDOW_LOADING); + WindowUtils.recursiveSetVisible(loadingWindow,false); + WindowUtils.focusWindow(WindowStrings.WINDOW_MENU_MAIN); + WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), true); + } + + + protected static void loadCharacterServer(){ + Window loadingWindow = (Window)Globals.elementManager.getWindow(WindowStrings.WINDOW_LOADING); + WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), false); + WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); + loadingWindow.setVisible(true); + //disable menu input + Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.NO_INPUT); + //initialize the client thread (client) + initClientThread(); + //while we don't know what races are playable, wait + while(Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces().size() == 0){ + try { + TimeUnit.MILLISECONDS.sleep(5); + } catch (InterruptedException ex) {} + } + //once we have them, bring up the character creation interface + //init character creation window + //eventually should replace with at ui to select an already created character or create a new one + WindowUtils.replaceMainMenuContents(MenuGeneratorsMultiplayer.createMultiplayerCharacterCreationWindow()); + //make loading dialog disappear + loadingWindow.setVisible(false); + //make character creation window visible + WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), true); + //recapture window + Globals.controlHandler.setShouldRecapture(true); + //log + LoggerInterface.loggerEngine.INFO("[Client]Finished loading character creation menu"); + //set menu controls again + Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.TITLE_MENU); + } + + + protected static void loadClientWorld(){ + Window loadingWindow = (Window)Globals.elementManager.getWindow(WindowStrings.WINDOW_LOADING); + WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), false); + WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); + loadingWindow.setVisible(true); + //disable menu input + Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.NO_INPUT); + //collision engine + if(!Globals.RUN_SERVER){ + LoadingUtils.initCommonWorldData(Globals.RUN_SERVER); + } + //initialize the "real" objects simulation + initClientSimulation(); + //initialize the cell manager (client) + initDrawCellManager(); + //initialize the basic graphical entities of the world (skybox, camera) + initWorldBaseGraphicalEntities(); + //init arena specific stuff (ie different skybox colors) + initArenaGraphicalEntities(); + //sets micro and macro sims to ready if they exist + setSimulationsToReady(); + //init culling manager and other graphics-focused non-simulation items + initEntitycullingManager(); + //hide cursor + Globals.controlHandler.hideMouse(); + //make loading window disappear + loadingWindow.setVisible(false); + //recapture screen + Globals.controlHandler.setShouldRecapture(true); + //set rendering flags to main game mode + Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true; + Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = true; + Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = true; + Globals.RENDER_FLAG_RENDER_UI = true; + Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false; + Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false; + LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game"); + //set controls state + Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.MAIN_GAME); + } + + + + + + + + + + + private static void initClientThread(){ + //start client networking + Thread clientThread = null; + if(Globals.RUN_CLIENT){ + Globals.clientConnection = new ClientNetworking(NetUtils.getAddress(),NetUtils.getPort()); + clientThread = new Thread(Globals.clientConnection); + clientThread.start(); + } + } + + /** + * Creates client simulation object + */ + private static void initClientSimulation(){ + if(Globals.clientSimulation == null){ + Globals.clientSimulation = new ClientSimulation(); + } + } + + /** + * Sets client simulation object state to ready + */ + private static void setSimulationsToReady(){ + Globals.clientSimulation.setReady(true); + } + + + private static void initWorldBaseGraphicalEntities(){ + /* + + Skybox + + */ + // Model skyboxModel = Globals.assetManager.fetchModel(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC); + // Globals.skybox = EntityUtils.spawnDrawableEntity(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC); + + + /* + + Player Camera + + */ + Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); + // Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityAirplaneTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); + + + + /* + Targeting crosshair + */ + Crosshair.initCrossHairEntity(); + + } + + + static void initArenaGraphicalEntities(){ + + float skyR = 150; + float skyG = 200; + float skyB = 250; + + float groundR = 20; + float groundG = 20; + float groundB = 20; + + Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); + Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); + Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); + Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); + Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); + Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); + Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); + Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); + + //starry sky true skybox + Entity skybox = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(skybox, "Models/skyboxSphere.fbx"); + EntityUtils.getRotation(skybox).rotateX((float)(-Math.PI/2.0f)); + EntityUtils.getScale(skybox).mul(2000.0f); + Globals.assetManager.queueOverrideMeshShader("Models/skyboxSphere.fbx", "Sphere", "Shaders/skysphere/skysphere.vs", "Shaders/skysphere/skysphere.fs"); + + //cloud ring pseudo skybox + Entity cloudRing = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(cloudRing, "Models/cloudRing.fbx"); + EntityUtils.getRotation(cloudRing).rotateX((float)(-Math.PI/2.0f)); + EntityUtils.getScale(cloudRing).mul(1000.0f); + Globals.clientScene.registerBehaviorTree(new ApplyRotationTree(cloudRing,new Quaternionf().rotationZ(0.0001f))); + Globals.assetManager.queueOverrideMeshShader("Models/cloudRing.fbx", "Sphere", "Shaders/skysphere/skysphere.vs", "Shaders/skysphere/skysphere.fs"); + + } + + static void initDrawCellManager(){ + //initialize draw cell manager + Globals.drawCellManager = new DrawCellManager(Globals.commonWorldData, Globals.clientTerrainManager, 0, 0); + //set our draw cell manager to actually generate drawable chunks + Globals.drawCellManager.setGenerateDrawables(true); + //Alerts the client simulation that it should start loading terrain + Globals.clientSimulation.setLoadingTerrain(true); + //wait for all the terrain data to arrive + while(Globals.drawCellManager.containsInvalidCell()){ +// Globals.drawCellManager.updateInvalidCell(); + try { + TimeUnit.MILLISECONDS.sleep(10); + } catch (InterruptedException ex) { + } +// System.out.println("invalid cell"); + } + + while(Globals.drawCellManager.containsUndrawableCell()){ +// Globals.drawCellManager.makeCellDrawable(); + try { + TimeUnit.MILLISECONDS.sleep(10); + } catch (InterruptedException ex) { + } +// System.out.println("undrawable"); + } + + while(Globals.drawCellManager.containsPhysicsNeedingCell()){ + try { + TimeUnit.MILLISECONDS.sleep(10); + } catch (InterruptedException ex) { + } + } + // System.out.println("Draw Cell Manager ready"); + } + + private static void initEntitycullingManager(){ + Globals.clientEntityCullingManager = new ClientEntityCullingManager(Globals.clientScene); + } + + + + +} diff --git a/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java b/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java new file mode 100644 index 00000000..12cf0567 --- /dev/null +++ b/src/main/java/electrosphere/engine/loadingthreads/DebugSPWorldLoading.java @@ -0,0 +1,135 @@ +package electrosphere.engine.loadingthreads; + +import java.util.concurrent.TimeUnit; + +import org.joml.Vector3f; + +import electrosphere.auth.AuthenticationManager; +import electrosphere.engine.Globals; +import electrosphere.entity.types.camera.CameraEntityUtils; +import electrosphere.game.client.targeting.crosshair.Crosshair; +import electrosphere.game.server.terrain.manager.ServerTerrainManager; +import electrosphere.game.server.world.ServerWorldData; +import electrosphere.logger.LoggerInterface; +import electrosphere.menu.MenuGenerators; +import electrosphere.menu.WindowStrings; +import electrosphere.menu.WindowUtils; +import electrosphere.renderer.ui.Window; +import electrosphere.server.saves.SaveUtils; +import electrosphere.util.FileUtils; +import electrosphere.controls.ControlHandler; + +public class DebugSPWorldLoading { + + + protected static void loadDebugSPWorld(){ + Window loadingWindow = (Window)Globals.elementManager.getWindow(WindowStrings.WINDOW_LOADING); + //show loading + WindowUtils.recursiveSetVisible(Globals.elementManager.getWindow(WindowStrings.WINDOW_MENU_MAIN), false); + WindowUtils.replaceMainMenuContents(MenuGenerators.createEmptyMainMenu()); + loadingWindow.setVisible(true); + + Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,0.0f,0); + if(!SaveUtils.getSaves().contains("random_sp_world")){ + // + //the juicy server GENERATION part + // + //init save structure + SaveUtils.createOrOverwriteSave("random_sp_world"); + //create terrain + Globals.serverTerrainManager.generate(); + Globals.serverTerrainManager.save(SaveUtils.deriveSaveDirectoryPath("random_sp_world")); + //create world.json + Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); + FileUtils.serializeObjectToSavePath("random_sp_world", "./world.json", Globals.serverWorldData); + } + //load just-created save + SaveUtils.loadSave("random_sp_world"); + //start initializing game datastructures + // Globals.griddedDataCellManager.init(Globals.serverWorldData); + LoadingUtils.initGriddedRealm(); + //initialize the "virtual" objects simulation + LoadingUtils.initMacroSimulation(); + + + LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT); + //init the data of the world + // LoadingUtils.initTerrainDataCellManager(); + //init authentication + LoadingUtils.initAuthenticationManager(); + //initialize the local connection + Globals.clientUsername = "testuser"; + Globals.clientPassword = AuthenticationManager.getHashedString("testpass"); + LoadingUtils.initLocalConnection(); + //initialize the "real" objects simulation + LoadingUtils.initMicroSimulation(); + //collision engine + LoadingUtils.initCommonWorldData(Globals.RUN_SERVER); + //init game specific stuff (ie different skybox colors) + LoadingUtils.initGameGraphicalEntities(); + //set simulations to ready if they exist + LoadingUtils.setSimulationsToReady(); + //log + LoggerInterface.loggerEngine.INFO("[Server]Finished loading main world"); + + //the less juicy client setup part + while(Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces().size() == 0){ + try { + TimeUnit.MILLISECONDS.sleep(5); + } catch (InterruptedException ex) {} + } + + + LoadingUtils.spawnLocalPlayerTestEntity(); + + initWorldBaseGraphicalEntities(); + + // SeekTown.attachToCreature(Globals.playerEntity); + + //hide cursor + Globals.controlHandler.hideMouse(); + //make loading window disappear + loadingWindow.setVisible(false); + //recapture screen + Globals.controlHandler.setShouldRecapture(true); + //set rendering flags to main game mode + Globals.RENDER_FLAG_RENDER_SHADOW_MAP = true; + Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT = true; + Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER = true; + Globals.RENDER_FLAG_RENDER_UI = true; + Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND = false; + Globals.RENDER_FLAG_RENDER_WHITE_BACKGROUND = false; + LoggerInterface.loggerEngine.INFO("[Client]Finished loading main game"); + //set controls state + Globals.controlHandler.setHandlerState(ControlHandler.ControlsState.MAIN_GAME); + } + + + private static void initWorldBaseGraphicalEntities(){ + /* + + Skybox + + */ + // Model skyboxModel = Globals.assetManager.fetchModel(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC); + // Globals.skybox = EntityUtils.spawnDrawableEntity(AssetDataStrings.ASSET_STRING_SKYBOX_BASIC); + + + /* + + Player Camera + + */ + Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); + // Globals.playerCamera = CameraEntityUtils.spawnPlayerEntityAirplaneTrackingCameraEntity(new Vector3f(1,0,1), new Vector3f(0,0,1)); + + + + /* + Targeting crosshair + */ + Crosshair.initCrossHairEntity(); + + } + +} diff --git a/src/main/java/electrosphere/engine/loadingthreads/LoadingThread.java b/src/main/java/electrosphere/engine/loadingthreads/LoadingThread.java new file mode 100644 index 00000000..3924906f --- /dev/null +++ b/src/main/java/electrosphere/engine/loadingthreads/LoadingThread.java @@ -0,0 +1,71 @@ +package electrosphere.engine.loadingthreads; + +import java.util.concurrent.Semaphore; + +/** + * + * @author amaterasu + */ +public class LoadingThread extends Thread { + + public static final int LOAD_TITLE_MENU = 0; + public static final int LOAD_MAIN_GAME = 1; + public static final int LOAD_ARENA = 2; + public static final int LOAD_CHARACTER_SERVER = 3; + public static final int LOAD_CLIENT_WORLD = 4; + public static final int LOAD_DEBUG_RANDOM_SP_WORLD = 5; + + int threadType; + + Semaphore lock; + + public LoadingThread(int type){ + threadType = type; + lock = new Semaphore(1); + } + + @Override + public void run(){ + lock.acquireUninterruptibly(); + switch(threadType){ + + case LOAD_TITLE_MENU: { + ClientLoading.loadMainMenu(); + } break; + + case LOAD_MAIN_GAME: { + ServerLoading.loadMainGameServer(); + } break; + + case LOAD_ARENA: { + ArenaLoading.loadArenaGameServer(); + } break; + + case LOAD_CHARACTER_SERVER: { + ClientLoading.loadCharacterServer(); + } break; + + case LOAD_CLIENT_WORLD: { + ClientLoading.loadClientWorld(); + } break; + + + //intended to act like you went through the steps of setting up a vanilla settings SP world + case LOAD_DEBUG_RANDOM_SP_WORLD: { + DebugSPWorldLoading.loadDebugSPWorld(); + } break; + + } + lock.release(); + } + + + public boolean isDone(){ + boolean rVal = lock.tryAcquire(); + if(rVal == true){ + lock.release(); + } + return rVal; + } + +} diff --git a/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java new file mode 100644 index 00000000..bf85ca33 --- /dev/null +++ b/src/main/java/electrosphere/engine/loadingthreads/LoadingUtils.java @@ -0,0 +1,287 @@ +package electrosphere.engine.loadingthreads; + +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.util.concurrent.TimeUnit; + +import org.joml.Quaternionf; +import org.joml.Vector2i; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector3i; + +import electrosphere.auth.AuthenticationManager; +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.ServerEntityUtils; +import electrosphere.entity.state.movement.ApplyRotationTree; +import electrosphere.entity.types.creature.CreatureTemplate; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.game.client.cells.DrawCellManager; +import electrosphere.game.collision.CommonWorldData; +import electrosphere.game.data.creature.type.CreatureType; +import electrosphere.game.data.creature.type.visualattribute.VisualAttribute; +import electrosphere.game.server.terrain.manager.ServerTerrainManager; +import electrosphere.game.server.town.Town; +import electrosphere.game.server.world.MacroData; +import electrosphere.game.server.world.ServerWorldData; +import electrosphere.net.NetUtils; +import electrosphere.net.client.ClientNetworking; +import electrosphere.net.server.Server; +import electrosphere.net.server.player.Player; +import electrosphere.server.datacell.GriddedDataCellManager; +import electrosphere.server.datacell.Realm; +import electrosphere.server.saves.SaveUtils; +import electrosphere.server.simulation.MacroSimulation; +import electrosphere.server.simulation.MicroSimulation; + +/** + * Utilities for all loading thread types + */ +public class LoadingUtils { + + // static void initTerrainDataCellManager(){ + // Globals.griddedDataCellManager.init(Globals.serverWorldData); + // } + + + + static void initServerGameTerrainManager(){ + + /* + Actually initialize the terrain manager + */ + float randomDampener = 0.0f; //0.25f; + Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,randomDampener,0); + if(Globals.RUN_SERVER){ + if(Globals.userSettings.gameplayGenerateWorld()){ + Globals.serverTerrainManager.generate(); + Globals.serverTerrainManager.save("./terrain.json"); + } else { + SaveUtils.loadSave(Globals.currentSaveName); + } + } + + /* + Set spawn point + */ + int playerStartX = 0; + int playerStartY = 0; + int discreteSize = Globals.serverTerrainManager.getWorldDiscreteSize(); + int chunkSize = Globals.serverTerrainManager.getChunkWidth(); + boolean found = false; + for(int x = 0; x < discreteSize; x++){ + for(int y = 0; y < discreteSize; y++){ + if(Globals.serverTerrainManager.getDiscreteValue(x, y)>1800){ + playerStartX = x; + playerStartY = y; + found = true; + } + if(found){ + break; + } + } + if(found){ + break; + } + } + +// Globals.spawnPoint = new Vector3f(playerStartX * chunkSize, Globals.serverTerrainManager.getHeightAtPosition(playerStartX * chunkSize,playerStartY * chunkSize), playerStartY * chunkSize); + + + + } + + static void initServerArenaTerrainManager(){ + Globals.serverTerrainManager = ServerTerrainManager.constructArenaTerrainManager(); + } + + static void initServerArenaWorldData(){ + Globals.serverWorldData = ServerWorldData.createArenaWorld(); + Globals.spawnPoint = new Vector3d(1,0.1,1); +// Globals.serverTerrainManager.getChunk(0, 0).addModification(new TerrainModification(0,0,5,5,5)); + } + + static void initServerGameWorldData(){ + Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); + } + + static void initCommonWorldData(boolean FLAG_INIT_SERVER){ + if(Globals.commonWorldData == null){ + if(FLAG_INIT_SERVER){ + Globals.commonWorldData = new CommonWorldData(Globals.serverWorldData, Globals.serverTerrainManager); + if(Globals.macroSimulation != null){ + Town startTown = Globals.macroData.getTowns().get(0); + Vector2i firstPos = startTown.getPositions().get(0); + // double startX = firstPos.x * Globals.serverTerrainManager.getChunkWidth(); + // double startZ = firstPos.y * Globals.serverTerrainManager.getChunkWidth(); + double startX = Globals.commonWorldData.convertWorldToReal(firstPos.x); + double startZ = Globals.commonWorldData.convertWorldToReal(firstPos.y); + Globals.spawnPoint.set((float)startX,(float)Globals.commonWorldData.getElevationAtPoint(new Vector3d(startX,0,startZ)),(float)startZ); + } + } else { + //basically wait for the client to receive the world metadata + while(!Globals.clientConnection.getClientProtocol().hasReceivedWorld()){ + try { + TimeUnit.MILLISECONDS.sleep(5); + } catch (InterruptedException ex) { + } + } + //then create common world data + Globals.commonWorldData = new CommonWorldData(Globals.clientWorldData, Globals.clientTerrainManager); + } + } + } + + + + static void initServerThread(){ + //start server networking + if(Globals.RUN_SERVER){ + Globals.server = new Server(NetUtils.getPort()); + Globals.serverThread = new Thread(Globals.server); + Globals.serverThread.start(); + } + } + + static void initAuthenticationManager(){ + if(Globals.RUN_SERVER){ + Globals.authenticationManager = new AuthenticationManager(); + } + } + + + + static void initClientThread(){ + //start client networking + Thread clientThread = null; + if(Globals.RUN_CLIENT){ + Globals.clientConnection = new ClientNetworking(NetUtils.getAddress(),NetUtils.getPort()); + clientThread = new Thread(Globals.clientConnection); + clientThread.start(); + } + } + + static void initLocalConnection(){ + Globals.server = new Server(NetUtils.getPort()); + try { + //client -> server pipe + PipedInputStream clientInput = new PipedInputStream(); + PipedOutputStream serverOutput = new PipedOutputStream(clientInput); + //server -> client pipe + PipedInputStream serverInput = new PipedInputStream(); + PipedOutputStream clientOutput = new PipedOutputStream(serverInput); + //start server communication thread + Globals.server.addLocalPlayer(serverInput, serverOutput); + //start client communication thread + Globals.clientConnection = new ClientNetworking(clientInput,clientOutput); + Thread clientThread = null; + clientThread = new Thread(Globals.clientConnection); + clientThread.start(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Spins up the gridded data cell manager + */ + protected static void initGriddedRealm(){ + Realm griddedRealm = Globals.realmManager.createGriddedRealm(Globals.serverWorldData); + } + + + static void initGameGraphicalEntities(){ + + + float skyR = 100; + float skyG = 150; + float skyB = 200; + + float groundR = 50; + float groundG = 100; + float groundB = 150; + + Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); + Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); + Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); + Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); + Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); + Globals.skyboxColors.add(new Vector3f(skyR,skyG,skyB)); + Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); + Globals.skyboxColors.add(new Vector3f(groundR,groundG,groundB)); + + } + + + /** + * Spawns the character, and sets server side connection player object values to the appropriate chunk + */ + static void spawnLocalPlayerTestEntity(){ + // + //Create entity + // + //send default template back + String race = Globals.gameConfigCurrent.getCreatureTypeLoader().getPlayableRaces().get(0); + CreatureType type = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(race); + CreatureTemplate template = new CreatureTemplate(race); + for(VisualAttribute attribute : type.getVisualAttributes()){ + if(attribute.getType().equals(VisualAttribute.TYPE_BONE)){ + float min = attribute.getMinValue(); + float max = attribute.getMaxValue(); + float defaultValue = min + (max - min)/2.0f; + //add attribute to creature template + template.putValue(attribute.getAttributeId(), defaultValue); + } else if(attribute.getType().equals(VisualAttribute.TYPE_REMESH)){ + template.putValue(attribute.getAttributeId(), attribute.getVariants().get(0).getId()); + } + } + Realm realm = Globals.realmManager.getRealms().iterator().next(); + //spawn entity + Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,Globals.spawnPoint,template.getCreatureType(),template); + Globals.playerEntity = newPlayerEntity; + + //set player world-space coordinates + Player playerObject = Globals.playerManager.getPlayerFromId(0); + playerObject.setWorldPos(new Vector3i( + Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x), + Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.y), + Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z) + )); + //set client entity data + Globals.clientPlayerData.setWorldPos(playerObject.getWorldPos()); + //initially position entity + ServerEntityUtils.initiallyPositionEntity(realm, newPlayerEntity, new Vector3d(Globals.spawnPoint.x + 1,Globals.spawnPoint.y + 5,Globals.spawnPoint.z + 1)); + //add entity to correct cells + realm.getDataCellManager().addPlayerToRealm(playerObject); + } + + static void initMacroSimulation(){ + Globals.macroData = MacroData.generateWorld(0); +// Globals.macroData.describeWorld(); + Globals.macroSimulation = new MacroSimulation(); + Globals.macroSimulation.simulate(); +// Town startTown = Globals.macroData.getTowns().get(0); +// Vector2i firstPos = startTown.getPositions().get(0); +// double startX = firstPos.x * Globals.serverTerrainManager.getChunkWidth(); +// double startZ = firstPos.y * Globals.serverTerrainManager.getChunkWidth(); +// Globals.spawnPoint.set((float)startX,(float)Globals.commonWorldData.getElevationAtPoint(new Vector3d(startX,0,startZ)),(float)startZ); +// Globals.macroSimulation.setReady(true); + } + + static void initMicroSimulation(){ + if(Globals.microSimulation == null){ + Globals.microSimulation = new MicroSimulation(); + } + } + + static void setSimulationsToReady(){ + Globals.microSimulation.setReady(true); + if(Globals.macroSimulation != null){ + Globals.macroSimulation.setReady(true); + } + } + +} diff --git a/src/main/java/electrosphere/engine/loadingthreads/ServerLoading.java b/src/main/java/electrosphere/engine/loadingthreads/ServerLoading.java new file mode 100644 index 00000000..4b98c481 --- /dev/null +++ b/src/main/java/electrosphere/engine/loadingthreads/ServerLoading.java @@ -0,0 +1,45 @@ +package electrosphere.engine.loadingthreads; + +import electrosphere.engine.Globals; +import electrosphere.game.server.terrain.manager.ServerTerrainManager; +import electrosphere.logger.LoggerInterface; +import electrosphere.server.saves.SaveUtils; + +public class ServerLoading { + + + protected static void loadMainGameServer(){ +//initialize the terrain manager (server only) +// if(Globals.RUN_SERVER){ +// initServerGameTerrainManager(); +// } + + //TODO: Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,randomDampener,0); + Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,0.0f,0); + SaveUtils.loadSave(Globals.currentSaveName); + // LoadingUtils.initTerrainDataCellManager(); + //TODO: set spawnpoint + //TODO: Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); + //TODO: Globals.dataCellManager = new DataCellManager(Globals.serverWorldData); +// Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); +// Globals.dataCellManager = new DataCellManager(Globals.serverWorldData); + LoggerInterface.loggerEngine.INFO("run server: " + Globals.RUN_SERVER + " run client: " + Globals.RUN_CLIENT); + //init authentication + LoadingUtils.initAuthenticationManager(); + //initialize the server thread (server only) + LoadingUtils.initServerThread(); + //initialize the "virtual" objects simulation + LoadingUtils.initMacroSimulation(); + //initialize the "real" objects simulation + LoadingUtils.initMicroSimulation(); + //collision engine + LoadingUtils.initCommonWorldData(Globals.RUN_SERVER); + //init game specific stuff (ie different skybox colors) + LoadingUtils.initGameGraphicalEntities(); + //set simulations to ready if they exist + LoadingUtils.setSimulationsToReady(); + //log + LoggerInterface.loggerEngine.INFO("[Server]Finished loading main world"); + } + +} diff --git a/src/main/java/electrosphere/entity/ClientEntityUtils.java b/src/main/java/electrosphere/entity/ClientEntityUtils.java new file mode 100644 index 00000000..2a31178b --- /dev/null +++ b/src/main/java/electrosphere/entity/ClientEntityUtils.java @@ -0,0 +1,25 @@ +package electrosphere.entity; + +import org.joml.Vector3d; + +import electrosphere.entity.types.collision.CollisionObjUtils; + +/** + * Client only entity utility functions + */ +public class ClientEntityUtils { + + + + /** + * Called when the creature is first spawned to serialize to all people in its initial chunk + * @param entity + * @param position + */ + public static void initiallyPositionEntity(Entity entity, Vector3d position){ + //reposition entity + CollisionObjUtils.positionCharacter(entity, position); + } + + +} diff --git a/src/main/java/electrosphere/entity/Entity.java b/src/main/java/electrosphere/entity/Entity.java index 537467c9..8fda431c 100644 --- a/src/main/java/electrosphere/entity/Entity.java +++ b/src/main/java/electrosphere/entity/Entity.java @@ -46,11 +46,8 @@ public class Entity { return data.get(key); } - public Entity(){ + protected Entity(){ data = new HashMap(); - while(Globals.entityManager.getEntityFromId(entity_id_iterator)!=null){ - entity_id_iterator++; - } id = entity_id_iterator; entity_id_iterator++; } diff --git a/src/main/java/electrosphere/entity/EntityCreationUtils.java b/src/main/java/electrosphere/entity/EntityCreationUtils.java new file mode 100644 index 00000000..a69cdd48 --- /dev/null +++ b/src/main/java/electrosphere/entity/EntityCreationUtils.java @@ -0,0 +1,105 @@ +package electrosphere.entity; + +import org.joml.Quaternionf; +import org.joml.Vector3d; +import org.joml.Vector3f; + +import electrosphere.engine.Globals; +import electrosphere.renderer.actor.ActorUtils; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.datacell.utils.EntityLookupUtils; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; +import electrosphere.server.poseactor.PoseActor; + +public class EntityCreationUtils { + + /** + * Creates a server entity in the given realm and position. This uses spatial entity as a server entity can't (currently) exist outside of a realm. + * @param realm The realm to attach the entity to + * @param position The position to place the entity at + * @return The entity + */ + public static Entity createServerEntity(Realm realm, Vector3d position){ + Entity rVal = EntityUtils.spawnSpatialEntity(); + //register to global entity id lookup table + EntityLookupUtils.registerServerEntity(rVal); + //register to data cell + ServerDataCell entityDataCell = realm.getDataCellManager().tryCreateCellAtPoint(position); + entityDataCell.getScene().registerEntity(rVal); + //maps this entity to its realm + Globals.realmManager.mapEntityToRealm(rVal, realm); + //enable behavior tree tracking + ServerBehaviorTreeUtils.registerEntity(rVal); + //register to entity data cell mapper + realm.getEntityDataCellMapper().registerEntity(rVal, entityDataCell); + + return rVal; + } + + /** + * Spawns an entity that is not attached to a realm (for instance an item in an inventory) + * @return The entity + */ + public static Entity createRealmlessServerEntity(){ + Entity rVal = new Entity(); + //register to global entity id lookup table + EntityLookupUtils.registerServerEntity(rVal); + //enable behavior tree tracking + ServerBehaviorTreeUtils.registerEntity(rVal); + return rVal; + } + + /** + * Creates an entity for the client + * @return The entity + */ + public static Entity createClientSpatialEntity(){ + Entity rVal = EntityUtils.spawnSpatialEntity(); + Globals.clientSceneWrapper.getScene().registerEntity(rVal); + return rVal; + } + + /** + * Creates a non-spatial entity for the client + * @return The entity + */ + public static Entity createClientNonSpatialEntity(){ + Entity rVal = new Entity(); + Globals.clientSceneWrapper.getScene().registerEntity(rVal); + return rVal; + } + + + /** + * Makes an already created entity a poseable entity by backing it with a PoseActor + * @param entity The entity + * @param modelPath The model path for the model to back the pose actor + */ + public static void makeEntityPoseable(Entity entity, String modelPath){ + entity.putData(EntityDataStrings.POSE_ACTOR, new PoseActor(modelPath)); + entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); + entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaternionf().identity()); + entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); + entity.putData(EntityDataStrings.DATA_STRING_DRAW, true); + entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true); + } + + + /** + * MAkes an already created entity a drawable entity (client only) by backing it with an Actor + * @param entity The entity + * @param modelPath The model path for the model to back the actor + */ + public static void makeEntityDrawable(Entity entity, String modelPath){ + entity.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorFromModelPath(modelPath)); + entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); + entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaternionf().identity()); + entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); + entity.putData(EntityDataStrings.DATA_STRING_DRAW, true); + entity.putData(EntityDataStrings.DRAW_SOLID_PASS, true); + Globals.clientScene.registerEntity(entity); + Globals.clientScene.registerEntityToTag(entity, EntityTags.DRAWABLE); + } + +} diff --git a/src/main/java/electrosphere/entity/EntityDataStrings.java b/src/main/java/electrosphere/entity/EntityDataStrings.java index 3fa704aa..8ec26c74 100644 --- a/src/main/java/electrosphere/entity/EntityDataStrings.java +++ b/src/main/java/electrosphere/entity/EntityDataStrings.java @@ -35,15 +35,19 @@ public class EntityDataStrings { public static final String DATA_STRING_CREATURE_IS_CREATURE = "isCreature"; public static final String DATA_STRING_CREATURE_TYPE = "creatureType"; public static final String DATA_STRING_CREATURE_CONTROLLER_PLAYER_ID = "creaturePlayerId"; - public static final String DATA_STRING_MOVEMENT_BT = "movementBT"; - public static final String SPRINT_TREE = "sprintBT"; + public static final String CLIENT_MOVEMENT_BT = "clientMovementBT"; + public static final String SERVER_MOVEMENT_BT = "serverMovementBT"; + public static final String CLIENT_SPRINT_TREE = "clientSprintBT"; + public static final String SERVER_SPRINT_TREE = "serverSprintBT"; public static final String DATA_STRING_FACING_VECTOR = "facingVector"; public static final String DATA_STRING_VELOCITY = "velocity"; public static final String DATA_STRING_ACCELERATION = "acceleration"; public static final String DATA_STRING_MAX_NATURAL_VELOCITY = "velocityMaxNatural"; public static final String CREATURE_ATTRIBUTE_VARIANT = "creatureAttributeVariant"; - public static final String ROTATOR_TREE = "rotatorTree"; - public static final String JUMP_TREE = "jumpTree"; + public static final String CLIENT_ROTATOR_TREE = "clientRotatorTree"; + public static final String SERVER_ROTATOR_TREE = "serverRotatorTree"; + public static final String CLIENT_JUMP_TREE = "clientJumpTree"; + public static final String SERVER_JUMP_TREE = "serverJumpTree"; public static final String FALL_TREE = "fallTree"; public static final String CREATURE_TEMPLATE = "creatureTemplate"; @@ -110,7 +114,8 @@ public class EntityDataStrings { Gravity Entity */ public static final String GRAVITY_ENTITY = "gravityEntity"; - public static final String GRAVITY_TREE = "gravityTree"; + public static final String CLIENT_GRAVITY_TREE = "clientGravityTree"; + public static final String SERVER_GRAVITY_TREE = "serverGravityTree"; /* Collision Entity @@ -134,7 +139,8 @@ public class EntityDataStrings { public static final String COLLISION_ENTITY_DATA_PARENT = "collisionDataParent"; - public static final String COLLIDABLE_TREE = "collidableTree"; + public static final String SERVER_COLLIDABLE_TREE = "serverCollidableTree"; + public static final String CLIENT_COLLIDABLE_TREE = "clientCollidableTree"; public static final String HITBOX_DATA = "hitboxData"; public static final String HITBOX_ASSOCIATED_LIST = "hitboxAssociatedList"; @@ -170,7 +176,8 @@ public class EntityDataStrings { /* Attack behavior tree */ - public static final String ATTACK_TREE = "attackTree"; + public static final String CLIENT_ATTACK_TREE = "clientAttackTree"; + public static final String SERVER_ATTACK_TREE = "serverAttackTree"; public static final String ATTACK_MOVE_TYPE_ACTIVE = "attackMoveTypeActive"; public static final String ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND = "MELEE_WEAPON_SWING_ONE_HAND"; @@ -225,7 +232,8 @@ public class EntityDataStrings { Inventory in general */ public static final String NATURAL_INVENTORY = "inventoryNatural"; - public static final String INVENTORY_STATE = "inventoryState"; + public static final String CLIENT_INVENTORY_STATE = "clientInventoryState"; + public static final String SERVER_INVENTORY_STATE = "serverInventoryState"; /* Iron sight @@ -236,6 +244,11 @@ public class EntityDataStrings { AI stuff */ public static final String VIEW_PITCH = "aiViewPitch"; + + /** + * Pose actor + */ + public static final String POSE_ACTOR = "poseActor"; /* Entity categories diff --git a/src/main/java/electrosphere/entity/EntityUtils.java b/src/main/java/electrosphere/entity/EntityUtils.java index b63effff..fb52bf9b 100644 --- a/src/main/java/electrosphere/entity/EntityUtils.java +++ b/src/main/java/electrosphere/entity/EntityUtils.java @@ -6,7 +6,6 @@ package electrosphere.entity; import electrosphere.engine.Globals; -import electrosphere.entity.state.collidable.CollidableTree; import electrosphere.entity.state.movement.GroundMovementTree; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.creature.CreatureUtils; @@ -14,7 +13,11 @@ import electrosphere.entity.types.item.ItemUtils; import electrosphere.renderer.Model; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.ActorUtils; +import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.datacell.utils.DataCellSearchUtils; +import electrosphere.server.datacell.utils.EntityLookupUtils; +import electrosphere.server.poseactor.PoseActor; import org.joml.Quaternionf; import org.joml.Vector3d; @@ -42,7 +45,12 @@ public class EntityUtils { return (String)e.getData(EntityDataStrings.DATA_STRING_MODEL_PATH); } - public static Entity spawnDrawableEntity(String modelPath){ + /** + * Creates an entity with an associated actor + * @param modelPath The model path of the model for the actor + * @return The entity + */ + protected static Entity spawnDrawableEntity(String modelPath){ Entity rVal = new Entity(); rVal.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorFromModelPath(modelPath)); // rVal.putData(EntityDataStrings.DATA_STRING_MODEL_PATH, modelPath); @@ -51,12 +59,17 @@ public class EntityUtils { rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); rVal.putData(EntityDataStrings.DRAW_SOLID_PASS, true); - Globals.entityManager.registerEntity(rVal); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.DRAWABLE); + Globals.clientScene.registerEntity(rVal); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.DRAWABLE); return rVal; } - public static Entity spawnDrawableEntityWithPreexistingModel(String modelPath){ + /** + * Creates an entity with an actor based on a model that already exists or is actively being loaded, not sure + * @param modelPath The path to the model in asset manager + * @return The entity + */ + protected static Entity spawnDrawableEntityWithPreexistingModel(String modelPath){ Entity rVal = new Entity(); rVal.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorOfLoadingModel(modelPath)); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); @@ -64,20 +77,37 @@ public class EntityUtils { rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); rVal.putData(EntityDataStrings.DRAW_SOLID_PASS, true); - Globals.entityManager.registerEntity(rVal); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.DRAWABLE); + Globals.clientScene.registerEntity(rVal); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.DRAWABLE); + return rVal; + } + + /** + * Spawns an entity with a backing pose actor (server side presumably) + * @param modelPath The model path to back the pose actor + * @return The entity + */ + protected static Entity spawnPoseableEntity(String modelPath){ + Entity rVal = new Entity(); + rVal.putData(EntityDataStrings.POSE_ACTOR, new PoseActor(modelPath)); +// rVal.putData(EntityDataStrings.DATA_STRING_MODEL_PATH, modelPath); + rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); + rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaternionf().identity()); + rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); + rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); + rVal.putData(EntityDataStrings.DRAW_SOLID_PASS, true); return rVal; } - public static Entity spawnUIEntity(String modelPath){ + protected static Entity spawnUIEntity(String modelPath){ Entity rVal = new Entity(); rVal.putData(EntityDataStrings.DATA_STRING_ACTOR, ActorUtils.createActorFromModelPath(modelPath)); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaternionf().rotateAxis((float)0, new Vector3f(1,0,0))); rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); rVal.putData(EntityDataStrings.DATA_STRING_UI_ELEMENT, true); - Globals.entityManager.registerEntity(rVal); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.UI); + Globals.clientScene.registerEntity(rVal); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.UI); return rVal; } @@ -85,21 +115,32 @@ public class EntityUtils { * Spawns an entity that has a position in the world, but isn't necessarily drawable * @return the entity */ - public static Entity spawnSpatialEntity(){ + protected static Entity spawnSpatialEntity(){ Entity rVal = new Entity(); // rVal.putData(EntityDataStrings.DATA_STRING_MODEL_PATH, modelPath); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaternionf().identity()); rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1)); - Globals.entityManager.registerEntity(rVal); + EntityLookupUtils.registerServerEntity(rVal); return rVal; } - public static void cleanUpDrawableEntity(Entity e){ - if(e != null){ - Globals.entityManager.deregisterEntity(e); -// getEntityModelPath(e).free(); + /** + * Cleans up the entity and deregisters it from all tracking datastructures + * @param e The entity to clean up + */ + public static void cleanUpEntity(Entity e){ + //remove from client + Globals.clientSceneWrapper.getScene().deregisterEntity(e); + //remove from all server classes + if(Globals.realmManager != null){ + Realm realm = Globals.realmManager.getEntityRealm(e); + if(realm != null){ + realm.getEntityDataCellMapper().ejectEntity(e); + } + Globals.realmManager.removeEntity(e); } + EntityLookupUtils.removeEntity(e); } // public static void setEntityID(Entity e, int id){ @@ -109,6 +150,10 @@ public class EntityUtils { public static Actor getActor(Entity e){ return (Actor)e.getData(EntityDataStrings.DATA_STRING_ACTOR); } + + public static PoseActor getPoseActor(Entity e){ + return (PoseActor)e.getData(EntityDataStrings.POSE_ACTOR); + } public static void setVisible(Entity entity, boolean visible){ entity.putData(EntityDataStrings.DATA_STRING_DRAW, visible); @@ -121,65 +166,5 @@ public class EntityUtils { public static boolean getDraw(Entity entity){ return (boolean)entity.getData(EntityDataStrings.DATA_STRING_DRAW); } - - /** - * Called when the creature is first spawned to serialize to all people in its initial chunk - * @param entity - * @param position - */ - public static void initiallyPositionEntity(Entity entity, Vector3d position){ - //if server, get current server data cell - if(Globals.RUN_SERVER){ - ServerDataCell oldDataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(entity)); - ServerDataCell newDataCell = Globals.dataCellManager.getDataCellAtPoint(position); - if(newDataCell != null){ - //initialize server datacell tracking of this entity - Globals.dataCellManager.initializeServerSideEntity(entity, newDataCell); - } else { - //if it doesn't already exist, try creating it and if successfull move creature - newDataCell = Globals.dataCellManager.tryCreateGroundDataCell(EntityUtils.getPosition(entity)); - //initialize server datacell tracking of this entity - Globals.dataCellManager.initializeServerSideEntity(entity, newDataCell); - } - //if the server is also a client, update the drawcell manager to know to pull new chunks - if(Globals.RUN_CLIENT){ - Globals.drawCellManager.invalidateAllCells(); - Globals.drawCellManager.setCellX(Globals.clientPlayerData.getWorldPositionX()); - Globals.drawCellManager.setCellY(Globals.clientPlayerData.getWorldPositionY()); - } - } - //reposition entity - CollisionObjUtils.positionCharacter(entity, position); - } - - /** - * Called to reposition the creature - * @param entity - * @param position - */ - public static void repositionEntity(Entity entity, Vector3d position){ - //if server, get current server data cell - if(Globals.RUN_SERVER){ - ServerDataCell oldDataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(entity)); - ServerDataCell newDataCell = Globals.dataCellManager.getDataCellAtPoint(position); - if(newDataCell != null){ - ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell); - } else { - //if it doesn't already exist, try creating it and if successfull move creature - newDataCell = Globals.dataCellManager.tryCreateGroundDataCell(EntityUtils.getPosition(entity)); - if(newDataCell != null){ - ServerDataCell.moveEntityFromCellToCell(entity, oldDataCell, newDataCell); - } - } - //if the server is also a client, update the drawcell manager to know to pull new chunks - if(Globals.RUN_CLIENT){ - Globals.drawCellManager.invalidateAllCells(); - Globals.drawCellManager.setCellX(Globals.clientPlayerData.getWorldPositionX()); - Globals.drawCellManager.setCellY(Globals.clientPlayerData.getWorldPositionY()); - } - } - //reposition entity - CollisionObjUtils.positionCharacter(entity, Globals.spawnPoint); - } } diff --git a/src/main/java/electrosphere/entity/Scene.java b/src/main/java/electrosphere/entity/Scene.java index e473f848..1867f835 100644 --- a/src/main/java/electrosphere/entity/Scene.java +++ b/src/main/java/electrosphere/entity/Scene.java @@ -6,10 +6,12 @@ import electrosphere.entity.types.attach.AttachUtils; import electrosphere.logger.LoggerInterface; import java.lang.reflect.Field; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import org.joml.Vector3d; @@ -23,30 +25,32 @@ public class Scene { Map entityIdMap = new ConcurrentHashMap(); - Map clientToServerIdMap = new ConcurrentHashMap(); - Map serverToClientIdMap = new ConcurrentHashMap(); - Map> tagEntityMap = new ConcurrentHashMap>(); + Map> tagEntityMap = new ConcurrentHashMap>(); List entityList = new CopyOnWriteArrayList(); List behaviorTreeList = new CopyOnWriteArrayList(); public Scene(){ - tagEntityMap.put(EntityTags.BONE_ATTACHED, new LinkedList()); - tagEntityMap.put(EntityTags.COLLIDABLE, new LinkedList()); - tagEntityMap.put(EntityTags.SPRINTABLE, new LinkedList()); - tagEntityMap.put(EntityTags.MOVEABLE, new LinkedList()); - tagEntityMap.put(EntityTags.ATTACKER, new LinkedList()); - tagEntityMap.put(EntityTags.TARGETABLE, new LinkedList()); - tagEntityMap.put(EntityTags.LIFE_STATE, new LinkedList()); - tagEntityMap.put(EntityTags.CREATURE, new LinkedList()); - tagEntityMap.put(EntityTags.UI, new LinkedList()); - tagEntityMap.put(EntityTags.DRAWABLE, new LinkedList()); - tagEntityMap.put(EntityTags.LIGHT, new LinkedList()); - tagEntityMap.put(EntityTags.ITEM, new LinkedList()); - tagEntityMap.put(EntityTags.GRAVITY, new LinkedList()); - tagEntityMap.put(EntityTags.PARTICLE, new LinkedList()); + tagEntityMap.put(EntityTags.BONE_ATTACHED, new HashSet()); + tagEntityMap.put(EntityTags.COLLIDABLE, new HashSet()); + tagEntityMap.put(EntityTags.SPRINTABLE, new HashSet()); + tagEntityMap.put(EntityTags.MOVEABLE, new HashSet()); + tagEntityMap.put(EntityTags.ATTACKER, new HashSet()); + tagEntityMap.put(EntityTags.TARGETABLE, new HashSet()); + tagEntityMap.put(EntityTags.LIFE_STATE, new HashSet()); + tagEntityMap.put(EntityTags.CREATURE, new HashSet()); + tagEntityMap.put(EntityTags.UI, new HashSet()); + tagEntityMap.put(EntityTags.DRAWABLE, new HashSet()); + tagEntityMap.put(EntityTags.LIGHT, new HashSet()); + tagEntityMap.put(EntityTags.ITEM, new HashSet()); + tagEntityMap.put(EntityTags.GRAVITY, new HashSet()); + tagEntityMap.put(EntityTags.PARTICLE, new HashSet()); } + /** + * Registers an entity to the scene + * @param e The entity to register + */ public void registerEntity(Entity e){ entityIdMap.put(e.getId(), e); entityList.add(e); @@ -61,7 +65,7 @@ public class Scene { if(tagEntityMap.containsKey(tag)){ tagEntityMap.get(tag).add(e); } else { - List newEntityList = new LinkedList(); + Set newEntityList = new HashSet(); newEntityList.add(e); tagEntityMap.put(tag,newEntityList); } @@ -72,7 +76,7 @@ public class Scene { * @param tag The tag * @return A list of all entities with the tag, or null if no entities have been added to the tag yet */ - public List getEntitiesWithTag(String tag){ + public Set getEntitiesWithTag(String tag){ return tagEntityMap.get(tag); } @@ -93,8 +97,14 @@ public class Scene { for(String key : tagEntityMap.keySet()){ tagEntityMap.get(key).remove(e); } + entityIdMap.remove(e.getId()); + entityList.remove(e); } + /** + * Recursively deregisters an entity and all entities attached via AttachUtils + * @param target The top level entity to deregister + */ public void recursiveDeregister(Entity target){ if(AttachUtils.hasChildren(target)){ List childrenList = AttachUtils.getChildrenList(target); @@ -105,123 +115,27 @@ public class Scene { deregisterEntity(target); } - public void recursiveHide(Entity target){ - if(AttachUtils.hasChildren(target)){ - List childrenList = AttachUtils.getChildrenList(target); - for(Entity currentChild : childrenList){ - recursiveHide(currentChild); - } - } - target.putData(EntityDataStrings.DATA_STRING_DRAW, false); - } - - public void recursiveShow(Entity target){ - if(AttachUtils.hasChildren(target)){ - List childrenList = AttachUtils.getChildrenList(target); - for(Entity currentChild : childrenList){ - recursiveShow(currentChild); - } - } - target.putData(EntityDataStrings.DATA_STRING_DRAW, true); - } - - // public void overrideEntityId(Entity e, int id){ - // LoggerInterface.loggerGameLogic.DEBUG("Overriding entity ID " + e.getId() + " => " + id); - // if(entityIdMap.containsKey(e.getId())){ - // entityIdMap.remove(e.getId()); - // } - // e.setId(id); - // entityIdMap.put(e.getId(), e); - // } - /** - * Registers a server provided ID as a mapping to a given ID on the client - * @param clientId The client's generated ID - * @param serverId The server's provided ID + * Gets an entity via its ID + * @param id The id to search for + * @return The entity with that ID */ - public void mapIdToId(int clientId, int serverId){ - LoggerInterface.loggerEngine.DEBUG("MapID: " + clientId + " <===> " + serverId); - clientToServerIdMap.put(clientId, serverId); - serverToClientIdMap.put(serverId, clientId); - } - - /** - * Resolves a client ID to the equivalent ID on the server - * @param clientId The id provided by the client - * @return The equivalent id on the server - */ - public int mapClientToServerId(int clientId){ - return clientToServerIdMap.get(clientId); - } - - /** - * Translates the id provided by the server into the equivalent id on the client - * @param serverId The id provided by the server - * @return The equivalent id on the client - */ - public int mapServerToClientId(int serverId){ - return serverToClientIdMap.get(serverId); - } - public Entity getEntityFromId(int id){ return (Entity)entityIdMap.get(id); } /** - * [CLIENT ONLY] Gets the entity provided a server-provided id - * @param id The server-provided ID - * @return The entity in question + * Registers a behavior tree to simulate each scene simulation frame + * @param tree The behavior tree to register */ - public Entity getEntityFromServerId(int id){ - if(Globals.RUN_SERVER){ - return (Entity)entityIdMap.get(id); - } else { - return (Entity)entityIdMap.get(mapServerToClientId(id)); - } - } - - public void clearOutOfBoundsEntities(){ - if(Globals.commonWorldData != null && Globals.playerEntity != null && Globals.clientPlayerData != null){ - Vector3d playerCharacterPos = EntityUtils.getPosition(Globals.playerEntity); - int playerCharacterWorldX = Globals.commonWorldData.convertRealToWorld(playerCharacterPos.x); - int playerCharacterWorldY = Globals.commonWorldData.convertRealToWorld(playerCharacterPos.z); - if(playerCharacterWorldX != Globals.clientPlayerData.getWorldPositionX() || playerCharacterWorldY != Globals.clientPlayerData.getWorldPositionY()){ - for(Entity entity : entityList){ - if(entity.containsKey(EntityDataStrings.TERRAIN_IS_TERRAIN) || entity.containsKey(EntityDataStrings.ATTACH_PARENT) || entity.containsKey(EntityDataStrings.COLLISION_ENTITY_PARENT)){ - - } else { - Vector3d position = EntityUtils.getPosition(entity); - //common world data is initialized with the collision data - //if this is null then the engine hasn't fully started up yet - if(position != null){ - int worldX = Globals.commonWorldData.convertRealToWorld(position.x); - int worldY = Globals.commonWorldData.convertRealToWorld(position.z); - if(!Globals.drawCellManager.coordsInPhysicsSpace(worldX, worldY)){ - //if we're running the server we need to just hide the entity - //otherwise delete it - if(Globals.RUN_SERVER && Globals.RUN_CLIENT){ - recursiveHide(entity); - } else { - recursiveDeregister(entity); - } - } else { - //if the entity is within range, we're running server, - //and it's not set to visible, make it visible - if(Globals.RUN_SERVER && Globals.RUN_CLIENT){ - recursiveShow(entity); - } - } - } - } - } - } - } - } - public void registerBehaviorTree(BehaviorTree tree){ behaviorTreeList.add(tree); } + /** + * Deregisters a behavior tree from the scene + * @param tree The behavior tree to deregister + */ public void deregisterBehaviorTree(BehaviorTree tree){ behaviorTreeList.remove(tree); } diff --git a/src/main/java/electrosphere/entity/ServerEntityUtils.java b/src/main/java/electrosphere/entity/ServerEntityUtils.java new file mode 100644 index 00000000..63af66cc --- /dev/null +++ b/src/main/java/electrosphere/entity/ServerEntityUtils.java @@ -0,0 +1,72 @@ +package electrosphere.entity; + +import org.joml.Vector3d; + +import electrosphere.engine.Globals; +import electrosphere.entity.types.collision.CollisionObjUtils; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.datacell.utils.DataCellSearchUtils; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; + +/** + * Entity utilities specifically for the server side + */ +public class ServerEntityUtils { + + /** + * Called when the creature is first spawned to serialize to all people in its initial chunk + * @param entity + * @param position + */ + public static void initiallyPositionEntity(Realm realm, Entity entity, Vector3d position){ + Globals.realmManager.mapEntityToRealm(entity, realm); + //get current server data cell + ServerDataCell cell = realm.getDataCellManager().getDataCellAtPoint(position); + if(cell != null){ + //initialize server datacell tracking of this entity + realm.initializeServerSideEntity(entity, cell); + } else { + //if it doesn't already exist, try creating it and if successfull move creature + cell = realm.getDataCellManager().tryCreateCellAtPoint(position); + //initialize server datacell tracking of this entity + realm.initializeServerSideEntity(entity, cell); + } + //reposition entity + CollisionObjUtils.positionCharacter(entity, position); + } + + /** + * Called to reposition the creature + * @param entity + * @param position + */ + public static void repositionEntity(Entity entity, Vector3d position){ + Realm realm = Globals.realmManager.getEntityRealm(entity); + //if server, get current server data cell + if(Globals.RUN_SERVER){ + ServerDataCell oldDataCell = realm.getDataCellManager().getDataCellAtPoint(EntityUtils.getPosition(entity)); + ServerDataCell newDataCell = realm.getDataCellManager().getDataCellAtPoint(position); + 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 the server is also a client, update the drawcell manager to know to pull new chunks + // if(Globals.RUN_CLIENT){ + // Globals.drawCellManager.invalidateAllCells(); + // Globals.drawCellManager.setCellX(Globals.clientPlayerData.getWorldPos().x); + // Globals.drawCellManager.setCellY(Globals.clientPlayerData.getWorldPos().z); + // } + } + //reposition entity + CollisionObjUtils.positionCharacter(entity, Globals.spawnPoint); + } + +} diff --git a/src/main/java/electrosphere/entity/ServerSceneManager.java b/src/main/java/electrosphere/entity/ServerSceneManager.java deleted file mode 100644 index dd6c8654..00000000 --- a/src/main/java/electrosphere/entity/ServerSceneManager.java +++ /dev/null @@ -1,12 +0,0 @@ -package electrosphere.entity; - -import java.util.LinkedList; -import java.util.List; - -public class ServerSceneManager { - - List scenes = new LinkedList(); - - - -} diff --git a/src/main/java/electrosphere/entity/scene/SceneLoader.java b/src/main/java/electrosphere/entity/scene/SceneLoader.java index 1885f8f9..ec32d874 100644 --- a/src/main/java/electrosphere/entity/scene/SceneLoader.java +++ b/src/main/java/electrosphere/entity/scene/SceneLoader.java @@ -1,11 +1,14 @@ package electrosphere.entity.scene; +import org.joml.Vector3d; + import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.object.ObjectUtils; +import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerDataCell; import electrosphere.util.FileUtils; @@ -19,7 +22,8 @@ public class SceneLoader { * @param path The path in the assets directory to a scene file */ public ServerDataCell serverInstantiateSceneFile(String path){ - ServerDataCell rVal = Globals.dataCellManager.createNewCell(); + Realm realm = Globals.realmManager.createRealm(); + ServerDataCell rVal = realm.createNewCell(); SceneFile file = FileUtils.loadObjectFromAssetPath(path, SceneFile.class); //spawn initial entities for(EntityDescriptor descriptor : file.getEntities()){ @@ -27,21 +31,22 @@ public class SceneLoader { switch(descriptor.getType()){ case EntityDescriptor.TYPE_CREATURE: { - Entity newEntity = CreatureUtils.spawnBasicCreature(descriptor.subtype, null); - EntityUtils.getPosition(newEntity).set(descriptor.posX,descriptor.posY,descriptor.posZ); + Vector3d position = new Vector3d(descriptor.posX,descriptor.posY,descriptor.posZ); + Entity newEntity = CreatureUtils.serverSpawnBasicCreature(realm, position, descriptor.subtype, null); EntityUtils.getRotation(newEntity).set((float)descriptor.rotX, (float)descriptor.rotY, (float)descriptor.rotZ, (float)descriptor.rotW); rVal.initializeEntityForNewPlayers(newEntity, rVal); } break; case EntityDescriptor.TYPE_ITEM: { - Entity newEntity = ItemUtils.spawnBasicItem(descriptor.subtype); - EntityUtils.getPosition(newEntity).set(descriptor.posX,descriptor.posY,descriptor.posZ); + Vector3d position = new Vector3d(descriptor.posX,descriptor.posY,descriptor.posZ); + Entity newEntity = ItemUtils.serverSpawnBasicItem(realm, position, descriptor.subtype); EntityUtils.getRotation(newEntity).set((float)descriptor.rotX, (float)descriptor.rotY, (float)descriptor.rotZ, (float)descriptor.rotW); rVal.initializeEntityForNewPlayers(newEntity, rVal); } break; case EntityDescriptor.TYPE_OBJECT: { - Entity newEntity = ObjectUtils.spawnBasicObject(descriptor.subtype); + Vector3d position = new Vector3d(descriptor.posX,descriptor.posY,descriptor.posZ); + Entity newEntity = ObjectUtils.serverSpawnBasicObject(realm, position, descriptor.subtype); EntityUtils.getPosition(newEntity).set(descriptor.posX,descriptor.posY,descriptor.posZ); EntityUtils.getRotation(newEntity).set((float)descriptor.rotX, (float)descriptor.rotY, (float)descriptor.rotZ, (float)descriptor.rotW); rVal.initializeEntityForNewPlayers(newEntity, rVal); diff --git a/src/main/java/electrosphere/entity/state/ParticleTree.java b/src/main/java/electrosphere/entity/state/ParticleTree.java index 84d47833..8a070be3 100644 --- a/src/main/java/electrosphere/entity/state/ParticleTree.java +++ b/src/main/java/electrosphere/entity/state/ParticleTree.java @@ -61,7 +61,7 @@ public class ParticleTree implements BehaviorTree { if(hasLife){ lifeCurrent--; if(lifeCurrent <= 0){ - Globals.entityManager.deregisterEntity(parent); + EntityUtils.cleanUpEntity(parent); } } } diff --git a/src/main/java/electrosphere/entity/state/attack/AttackTree.java b/src/main/java/electrosphere/entity/state/attack/AttackTree.java index 89c1215e..ed7ce250 100644 --- a/src/main/java/electrosphere/entity/state/attack/AttackTree.java +++ b/src/main/java/electrosphere/entity/state/attack/AttackTree.java @@ -5,6 +5,7 @@ import electrosphere.engine.Main; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; +import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.state.BehaviorTree; import electrosphere.entity.state.collidable.Impulse; import electrosphere.entity.state.equip.EquipState; @@ -22,6 +23,9 @@ import electrosphere.game.data.creature.type.equip.EquipPoint; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.anim.Animation; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.utils.EntityLookupUtils; + import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -117,8 +121,8 @@ public class AttackTree implements BehaviorTree { //intuit can hold from presence of windup anim currentMoveCanHold = currentMove.getHoldAnimationName() != null; //stop movement tree - if(parent.containsKey(EntityDataStrings.DATA_STRING_MOVEMENT_BT)){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(parent); + if(parent.containsKey(EntityDataStrings.CLIENT_MOVEMENT_BT)){ + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(parent); if(movementTree instanceof GroundMovementTree){ ((GroundMovementTree)movementTree).interrupt(); } @@ -233,8 +237,8 @@ public class AttackTree implements BehaviorTree { //state machine switch(state){ case WINDUP: - if(parent.containsKey(EntityDataStrings.ROTATOR_TREE)){ - RotatorTree.getRotatorTree(parent).setActive(true); + if(parent.containsKey(EntityDataStrings.CLIENT_ROTATOR_TREE)){ + RotatorTree.getClientRotatorTree(parent).setActive(true); } if(entityActor != null){ if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationName)){ @@ -249,25 +253,10 @@ public class AttackTree implements BehaviorTree { state = AttackTreeState.ATTACK; } } - if(Globals.RUN_SERVER){ - Globals.server.broadcastMessage( - EntityMessage.constructattackUpdateMessage( - parent.getId(), - System.currentTimeMillis(), - (float)position.x, - (float)position.y, - (float)position.z, - movementVector.x, - movementVector.y, - movementVector.z, - velocity, - 0 - ) - ); - } else if(Globals.RUN_CLIENT && parent.getId() == Globals.clientCharacterID){ + if(parent.getId() == Globals.clientCharacterID){ Globals.clientConnection.queueOutgoingMessage( EntityMessage.constructattackUpdateMessage( - Globals.entityManager.mapClientToServerId(parent.getId()), + Globals.clientSceneWrapper.mapClientToServerId(parent.getId()), System.currentTimeMillis(), (float)position.x, (float)position.y, @@ -291,37 +280,6 @@ public class AttackTree implements BehaviorTree { if(!stillHold){ state = AttackTreeState.ATTACK; } - // if(Globals.RUN_SERVER){ - // Globals.server.broadcastMessage( - // EntityMessage.constructattackUpdateMessage( - // parent.getId(), - // System.currentTimeMillis(), - // (float)position.x, - // (float)position.y, - // (float)position.z, - // movementVector.x, - // movementVector.y, - // movementVector.z, - // velocity, - // 0 - // ) - // ); - // } else if(Globals.RUN_CLIENT && parent.getId() == Globals.clientCharacterID){ - // Globals.clientConnection.queueOutgoingMessage( - // EntityMessage.constructattackUpdateMessage( - // parent.getId(), - // System.currentTimeMillis(), - // (float)position.x, - // (float)position.y, - // (float)position.z, - // movementVector.x, - // movementVector.y, - // movementVector.z, - // velocity, - // 0 - // ) - // ); - // } break; case ATTACK: if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){ @@ -365,31 +323,16 @@ public class AttackTree implements BehaviorTree { // EntityUtils.getRotation(currentEntity).rotationTo(new Vector3f(0,0,1), new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)).mul(parentActor.getBoneRotation(targetBone)).normalize(); } Vector3f initialVector = new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z).normalize(); - ProjectileUtils.spawnBasicProjectile(projectileToFire, spawnPosition, arrowRotation, 750, initialVector, 0.03f); + ProjectileUtils.clientSpawnBasicProjectile(projectileToFire, spawnPosition, arrowRotation, 750, initialVector, 0.03f); projectileToFire = null; } if(frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames()){ state = AttackTreeState.COOLDOWN; } - if(Globals.RUN_SERVER){ - Globals.server.broadcastMessage( - EntityMessage.constructattackUpdateMessage( - parent.getId(), - System.currentTimeMillis(), - (float)position.x, - (float)position.y, - (float)position.z, - movementVector.x, - movementVector.y, - movementVector.z, - velocity, - 1 - ) - ); - } else if(Globals.RUN_CLIENT && parent.getId() == Globals.clientCharacterID){ + if(parent.getId() == Globals.clientCharacterID){ Globals.clientConnection.queueOutgoingMessage( EntityMessage.constructattackUpdateMessage( - Globals.entityManager.mapClientToServerId(parent.getId()), + Globals.clientSceneWrapper.mapClientToServerId(parent.getId()), System.currentTimeMillis(), (float)position.x, (float)position.y, @@ -418,29 +361,14 @@ public class AttackTree implements BehaviorTree { if(frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames() + currentMove.getCooldownFrames()){ state = AttackTreeState.IDLE; frameCurrent = 0; - if(parent.containsKey(EntityDataStrings.ROTATOR_TREE)){ - RotatorTree.getRotatorTree(parent).setActive(false); + if(parent.containsKey(EntityDataStrings.CLIENT_ROTATOR_TREE)){ + RotatorTree.getClientRotatorTree(parent).setActive(false); } } - if(Globals.RUN_SERVER){ - Globals.server.broadcastMessage( - EntityMessage.constructattackUpdateMessage( - parent.getId(), - System.currentTimeMillis(), - (float)position.x, - (float)position.y, - (float)position.z, - movementVector.x, - movementVector.y, - movementVector.z, - velocity, - 2 - ) - ); - } else if(Globals.RUN_CLIENT && parent.getId() == Globals.clientCharacterID){ + if(parent.getId() == Globals.clientCharacterID){ Globals.clientConnection.queueOutgoingMessage( EntityMessage.constructattackUpdateMessage( - Globals.entityManager.mapClientToServerId(parent.getId()), + Globals.clientSceneWrapper.mapClientToServerId(parent.getId()), System.currentTimeMillis(), (float)position.x, (float)position.y, diff --git a/src/main/java/electrosphere/entity/state/attack/ServerAttackTree.java b/src/main/java/electrosphere/entity/state/attack/ServerAttackTree.java new file mode 100644 index 00000000..1bb91e48 --- /dev/null +++ b/src/main/java/electrosphere/entity/state/attack/ServerAttackTree.java @@ -0,0 +1,467 @@ +package electrosphere.entity.state.attack; + +import electrosphere.engine.Globals; +import electrosphere.engine.Main; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.ServerEntityUtils; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.collidable.Impulse; +import electrosphere.entity.state.equip.EquipState; +import electrosphere.entity.state.movement.GroundMovementTree; +import electrosphere.entity.state.movement.ServerGroundMovementTree; +import electrosphere.entity.state.rotator.RotatorTree; +import electrosphere.entity.state.rotator.ServerRotatorTree; +import electrosphere.entity.types.attach.AttachUtils; +import electrosphere.entity.types.collision.CollisionObjUtils; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.entity.types.hitbox.HitboxUtils; +import electrosphere.entity.types.item.ItemUtils; +import electrosphere.entity.types.projectile.ProjectileUtils; +import electrosphere.game.collision.collidable.Collidable; +import electrosphere.game.data.creature.type.attack.AttackMove; +import electrosphere.game.data.creature.type.equip.EquipPoint; +import electrosphere.net.parser.net.message.EntityMessage; +import electrosphere.renderer.actor.Actor; +import electrosphere.renderer.anim.Animation; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.utils.EntityLookupUtils; +import electrosphere.server.poseactor.PoseActor; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.joml.Quaterniond; +import org.joml.Quaternionf; +import org.joml.Quaternionfc; +import org.joml.Vector3d; +import org.joml.Vector3f; + +public class ServerAttackTree implements BehaviorTree { + + public static enum AttackTreeState { + WINDUP, + HOLD, + ATTACK, + COOLDOWN, + IDLE, + } + + //the state of drifting forward during the attack + public static enum AttackTreeDriftState { + DRIFT, + NO_DRIFT, + } + + AttackTreeState state; + AttackTreeDriftState driftState; + + Entity parent; + + CopyOnWriteArrayList networkMessageQueue = new CopyOnWriteArrayList(); + + long lastUpdateTime = 0; + + float frameCurrent; + + String animationName = "SwingWeapon"; + + int maxFrame = 60; + + List currentMoveset = null; + AttackMove currentMove = null; + Entity currentWeapon = null; + boolean currentMoveHasWindup; + boolean currentMoveCanHold; + boolean stillHold = true; + boolean firesProjectile = false; + String projectileToFire = null; + String attackingPoint = null; + + public ServerAttackTree(Entity e){ + state = AttackTreeState.IDLE; + driftState = AttackTreeDriftState.NO_DRIFT; + parent = e; + } + + public AttackTreeState getState(){ + return state; + } + + public void start(){ + currentMoveCanHold = false; + currentMoveHasWindup = false; + stillHold = true; + firesProjectile = false; + projectileToFire = null; + currentWeapon = null; + attackingPoint = null; + //figure out attack type we should be doing + String attackType = getAttackType(); + //if we can attack, setup doing so + if(canAttack(attackType)){ + parent.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, attackType); + currentMoveset = (List)parent.getData(attackType); + if(currentMoveset != null){ + if(currentMove == null){ + currentMove = currentMoveset.get(0); + } else { + currentMove = getNextMove(currentMoveset,currentMove.getNextMoveId()); + } + if(currentMove != null){ + firesProjectile = currentMove.getFiresProjectile(); + if(firesProjectile){ + projectileToFire = ItemUtils.getWeaponDataRaw(currentWeapon).getProjectileModel(); + } + + animationName = currentMove.getAttackAnimationName(); + //intuit windup from presence of windup anim + currentMoveHasWindup = currentMove.getWindupAnimationName() != null; + if(currentMoveHasWindup){ + animationName = currentMove.getWindupAnimationName(); + } + //intuit can hold from presence of windup anim + currentMoveCanHold = currentMove.getHoldAnimationName() != null; + //stop movement tree + if(parent.containsKey(EntityDataStrings.SERVER_MOVEMENT_BT)){ + BehaviorTree movementTree = CreatureUtils.serverGetEntityMovementTree(parent); + if(movementTree instanceof ServerGroundMovementTree){ + ((ServerGroundMovementTree)movementTree).interrupt(); + } + } + Vector3d movementVector = CreatureUtils.getFacingVector(parent); + EntityUtils.getRotation(parent).rotationTo(new Vector3f(0,0,1), new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z)); + //set initial stuff + state = AttackTreeState.WINDUP; + frameCurrent = 0; + } else { + state = AttackTreeState.IDLE; + } + } + } + } + + public void release(){ + stillHold = false; + } + + public void interrupt(){ + state = AttackTreeState.IDLE; + } + + public void slowdown(){ + state = AttackTreeState.COOLDOWN; + } + + @Override + public void simulate(float deltaTime){ + frameCurrent = frameCurrent + Main.deltaFrames; + float velocity = CreatureUtils.getVelocity(parent); + PoseActor entityPoseActor = EntityUtils.getPoseActor(parent); + Vector3d position = EntityUtils.getPosition(parent); + Vector3d movementVector = CreatureUtils.getFacingVector(parent); + + //parse attached network messages + for(EntityMessage message : networkMessageQueue){ + networkMessageQueue.remove(message); +// System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ()); + long updateTime = message.gettime(); + switch(message.getMessageSubtype()){ + case ATTACKUPDATE: + if(updateTime > lastUpdateTime){ + lastUpdateTime = updateTime; + switch(message.gettreeState()){ + case 0: + state = AttackTreeState.WINDUP; + frameCurrent = 0; + // System.out.println("Set state STARTUP"); + break; + case 1: + frameCurrent = currentMove.getWindupFrames()+1; + state = AttackTreeState.ATTACK; + // System.out.println("Set state MOVE"); + break; + case 2: + frameCurrent = currentMove.getWindupFrames()+currentMove.getAttackFrames()+1; + state = AttackTreeState.COOLDOWN; + // System.out.println("Set state SLOWDOWN"); + break; + case 3: + frameCurrent = 60; + state = AttackTreeState.IDLE; + // System.out.println("Set state IDLE"); + break; + } + } + EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); + CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ())); + break; + case ATTACHENTITYTOENTITY: + case CREATE: + case DESTROY: + case MOVE: + case MOVEUPDATE: + case SETBEHAVIORTREE: + case SETFACING: + case SETPOSITION: + case SETPROPERTY: + case KILL: + case SPAWNCREATURE: + //silently ignore + break; + } + } + + //handle the drifting if we're supposed to currently + switch(driftState){ + case DRIFT: + if(currentMove != null){ + //calculate the vector of movement + CollisionObjUtils.getCollidable(parent).addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), currentMove.getDriftGoal() * Main.deltaFrames, "movement")); + if(frameCurrent > currentMove.getDriftFrameEnd()){ + driftState = AttackTreeDriftState.NO_DRIFT; + } + } + break; + case NO_DRIFT: + if(currentMove != null){ + if(frameCurrent > currentMove.getDriftFrameStart() && frameCurrent < currentMove.getDriftFrameEnd()){ + driftState = AttackTreeDriftState.DRIFT; + } + } + break; + } + + // if(state != AttackTreeState.IDLE){ + // System.out.println(frameCurrent); + // } + + //state machine + switch(state){ + case WINDUP: + if(parent.containsKey(EntityDataStrings.SERVER_ROTATOR_TREE)){ + ServerRotatorTree.getServerRotatorTree(parent).setActive(true); + } + if(entityPoseActor != null){ + if(!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationName)){ + entityPoseActor.playAnimation(animationName,1); + entityPoseActor.incrementAnimationTime(0.0001); + } + } + if(frameCurrent > currentMove.getWindupFrames()){ + if(currentMoveCanHold && stillHold){ + state = AttackTreeState.HOLD; + } else { + state = AttackTreeState.ATTACK; + } + } + Globals.server.broadcastMessage( + EntityMessage.constructattackUpdateMessage( + parent.getId(), + System.currentTimeMillis(), + (float)position.x, + (float)position.y, + (float)position.z, + movementVector.x, + movementVector.y, + movementVector.z, + velocity, + 0 + ) + ); + break; + case HOLD: + if(entityPoseActor != null){ + if(!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationName)){ + entityPoseActor.playAnimation(animationName,1); + entityPoseActor.incrementAnimationTime(0.0001); + } + } + if(!stillHold){ + state = AttackTreeState.ATTACK; + } + break; + case ATTACK: + if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){ + List attachedEntities = AttachUtils.getChildrenList(parent); + for(Entity currentAttached : attachedEntities){ + if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){ + List hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached); + for(Entity hitbox : hitboxes){ + HitboxUtils.getHitboxData(hitbox).setActive(true); + } + } + } + } + if(firesProjectile && projectileToFire != null){ + //spawn projectile + //TODO: solve spawnPosition, initialVector + Vector3d spawnPosition = new Vector3d(0,0,0); + Quaternionf arrowRotation = new Quaternionf(); + String targetBone = null; + EquipState equipState = EquipState.getEquipState(parent); + EquipPoint weaponPoint = null; + if((weaponPoint = equipState.getEquipPoint(attackingPoint)) != null){ + targetBone = weaponPoint.getBone(); + } + if(targetBone != null){ + Actor parentActor = EntityUtils.getActor(parent); + //transform bone space + spawnPosition = new Vector3d(parentActor.getBonePosition(targetBone)); + spawnPosition = spawnPosition.mul(((Vector3f)EntityUtils.getScale(parent))); + Quaternionf rotation = EntityUtils.getRotation(parent); + spawnPosition = spawnPosition.rotate(new Quaterniond(rotation.x,rotation.y,rotation.z,rotation.w)); + //transform worldspace + spawnPosition.add(new Vector3d(EntityUtils.getPosition(parent))); + //set + // EntityUtils.getPosition(currentEntity).set(position); + //set rotation + // Quaternionf rotation = parentActor.getBoneRotation(targetBone); + // EntityUtils.getRotation(currentEntity).set(rotation).normalize(); + // Vector3d facingAngle = CreatureUtils.getFacingVector(parent); + arrowRotation = parentActor.getBoneRotation(targetBone); + // EntityUtils.getRotation(currentEntity).rotationTo(new Vector3f(0,0,1), new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)).mul(parentActor.getBoneRotation(targetBone)).normalize(); + } + Vector3f initialVector = new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z).normalize(); + Realm parentRealm = Globals.realmManager.getEntityRealm(parent); + ProjectileUtils.serverSpawnBasicProjectile(parentRealm, projectileToFire, spawnPosition, arrowRotation, 750, initialVector, 0.03f); + projectileToFire = null; + } + if(frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames()){ + state = AttackTreeState.COOLDOWN; + } + Globals.server.broadcastMessage( + EntityMessage.constructattackUpdateMessage( + parent.getId(), + System.currentTimeMillis(), + (float)position.x, + (float)position.y, + (float)position.z, + movementVector.x, + movementVector.y, + movementVector.z, + velocity, + 1 + ) + ); + break; + case COOLDOWN: + if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){ + List attachedEntities = AttachUtils.getChildrenList(parent); + for(Entity currentAttached : attachedEntities){ + if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){ + List hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached); + for(Entity hitbox : hitboxes){ + HitboxUtils.getHitboxData(hitbox).setActive(false); + } + } + } + } + if(frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames() + currentMove.getCooldownFrames()){ + state = AttackTreeState.IDLE; + frameCurrent = 0; + if(parent.containsKey(EntityDataStrings.SERVER_ROTATOR_TREE)){ + ServerRotatorTree.getServerRotatorTree(parent).setActive(false); + } + } + Globals.server.broadcastMessage( + EntityMessage.constructattackUpdateMessage( + parent.getId(), + System.currentTimeMillis(), + (float)position.x, + (float)position.y, + (float)position.z, + movementVector.x, + movementVector.y, + movementVector.z, + velocity, + 2 + ) + ); + break; + case IDLE: + currentMove = null; + currentMoveset = null; + break; + } + } + + public void addNetworkMessage(EntityMessage networkMessage) { + networkMessageQueue.add(networkMessage); + } + + String getAttackType(){ + String rVal = null; + if(EquipState.hasEquipState(parent)){ + EquipState equipState = EquipState.getEquipState(parent); + for(String point : equipState.equippedPoints()){ + Entity item = equipState.getEquippedItemAtPoint(point); + if(ItemUtils.isWeapon(item)){ + attackingPoint = point; + currentWeapon = item; + switch(ItemUtils.getWeaponClass(item)){ + case "sword1h": + rVal = EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND; + break; + case "bow2h": + rVal = EntityDataStrings.ATTACK_MOVE_TYPE_BOW_TWO_HAND; + break; + } + } + } + } + return rVal; + } + + boolean canAttack(String attackType){ + boolean rVal = true; + if(attackType == null){ + return false; + } else if(state != AttackTreeState.IDLE){ + //checks if we have a next move and if we're in the specified range of frames when we're allowed to chain into it + if( + currentMove.getNextMoveId() != null && + !currentMove.getNextMoveId().equals("") && + frameCurrent >= currentMove.getMoveChainWindowStart() && frameCurrent <= currentMove.getMoveChainWindowEnd() + ){ + rVal = true; + } + } else { + if(EquipState.hasEquipState(parent)){ + EquipState equipState = EquipState.getEquipState(parent); + // if(equipState.hasEquipPrimary()){ + // switch(attackType){ + // case EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND: + // break; + // default: + // rVal = false; + // break; + // } + // } else { + // switch(attackType){ + // case EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND: + // rVal = false; + // break; + // default: + // rVal = false; + // break; + // } + // } + } + } + return rVal; + } + + AttackMove getNextMove(List moveset, String nextMoveId){ + AttackMove rVal = null; + for(AttackMove move : moveset){ + if(move.getAttackMoveId().equals(nextMoveId)){ + rVal = move; + break; + } + } + return rVal; + } + +} diff --git a/src/main/java/electrosphere/entity/state/attack/ShooterTree.java b/src/main/java/electrosphere/entity/state/attack/ShooterTree.java index 727459bd..0fd22dce 100644 --- a/src/main/java/electrosphere/entity/state/attack/ShooterTree.java +++ b/src/main/java/electrosphere/entity/state/attack/ShooterTree.java @@ -2,12 +2,15 @@ package electrosphere.entity.state.attack; import org.joml.Vector3d; +import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.BehaviorTree; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.projectile.ProjectileUtils; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.utils.EntityLookupUtils; public class ShooterTree implements BehaviorTree { @@ -40,7 +43,12 @@ public class ShooterTree implements BehaviorTree { // Vector3d parentPosition = EntityUtils.getPosition(parent); Vector3d movementDir = CreatureUtils.getFacingVector(parent); - ProjectileUtils.spawnProjectile("missile1", parentPosition, new Vector3d(movementDir),parent); + if(EntityLookupUtils.isServerEntity(parent)){ + Realm parentRealm = Globals.realmManager.getEntityRealm(parent); + ProjectileUtils.serverSpawnProjectile(parentRealm, "missile1", parentPosition, new Vector3d(movementDir),parent); + } else { + ProjectileUtils.clientSpawnProjectile("missile1", parentPosition, new Vector3d(movementDir),parent); + } this.state = ShooterTreeState.COOLDOWN; cooldownCurrent = cooldownMax; } break; diff --git a/src/main/java/electrosphere/entity/state/collidable/CollidableTree.java b/src/main/java/electrosphere/entity/state/collidable/ClientCollidableTree.java similarity index 91% rename from src/main/java/electrosphere/entity/state/collidable/CollidableTree.java rename to src/main/java/electrosphere/entity/state/collidable/ClientCollidableTree.java index a55d3fba..547dfd12 100644 --- a/src/main/java/electrosphere/entity/state/collidable/CollidableTree.java +++ b/src/main/java/electrosphere/entity/state/collidable/ClientCollidableTree.java @@ -27,7 +27,7 @@ import org.joml.Vector4f; * * @author amaterasu */ -public class CollidableTree implements BehaviorTree { +public class ClientCollidableTree implements BehaviorTree { Entity parent; CollisionObject body; @@ -39,13 +39,13 @@ public class CollidableTree implements BehaviorTree { static final float DELTA_T = 0.01f; - public CollidableTree(Entity e, Collidable collidable, CollisionObject body){ + public ClientCollidableTree(Entity e, Collidable collidable, CollisionObject body){ parent = e; this.collidable = collidable; this.body = body; } - public CollidableTree(Entity e, Collidable collidable, CollisionObject body, boolean applyImpulses){ + public ClientCollidableTree(Entity e, Collidable collidable, CollisionObject body, boolean applyImpulses){ parent = e; this.collidable = collidable; this.body = body; @@ -73,14 +73,14 @@ public class CollidableTree implements BehaviorTree { // System.out.println("Position: " + position); } if(impulse.type.matches(Collidable.TYPE_ITEM)){ - if(parent.containsKey(EntityDataStrings.GRAVITY_TREE)){ - ((GravityTree)parent.getData(EntityDataStrings.GRAVITY_TREE)).start(); + if(parent.containsKey(EntityDataStrings.CLIENT_GRAVITY_TREE)){ + ((GravityTree)parent.getData(EntityDataStrings.CLIENT_GRAVITY_TREE)).start(); } } if(impulse.type.matches(Collidable.TYPE_CREATURE)){ // System.out.println(System.currentTimeMillis() + " creature hit!"); - if(parent.containsKey(EntityDataStrings.GRAVITY_TREE)){ - ((GravityTree)parent.getData(EntityDataStrings.GRAVITY_TREE)).start(); + if(parent.containsKey(EntityDataStrings.CLIENT_GRAVITY_TREE)){ + ((GravityTree)parent.getData(EntityDataStrings.CLIENT_GRAVITY_TREE)).start(); } } if( @@ -199,8 +199,8 @@ public class CollidableTree implements BehaviorTree { if(applyImpulses){ newPosition.add(offsetVector); } - if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){ - newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition); + if(!Globals.clientSceneWrapper.getCollisionEngine().checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){ + newPosition = Globals.clientSceneWrapper.getCollisionEngine().suggestMovementPosition(Globals.commonWorldData, parent, newPosition); } position.set(newPosition); @@ -224,12 +224,12 @@ public class CollidableTree implements BehaviorTree { return angularVelocity.lengthSquared(); } - public static boolean hasCollidableTree(Entity e){ - return e.containsKey(EntityDataStrings.COLLIDABLE_TREE); + public static boolean hasClientCollidableTree(Entity e){ + return e.containsKey(EntityDataStrings.CLIENT_COLLIDABLE_TREE); } - public static CollidableTree getCollidableTree(Entity e){ - return (CollidableTree)e.getData(EntityDataStrings.COLLIDABLE_TREE); + public static ClientCollidableTree getClientCollidableTree(Entity e){ + return (ClientCollidableTree)e.getData(EntityDataStrings.CLIENT_COLLIDABLE_TREE); } diff --git a/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java b/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java new file mode 100644 index 00000000..477f1961 --- /dev/null +++ b/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java @@ -0,0 +1,239 @@ +package electrosphere.entity.state.collidable; + +import electrosphere.collision.dispatch.CollisionObject; +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.gravity.GravityTree; +import electrosphere.entity.state.gravity.ServerGravityTree; +import electrosphere.entity.types.collision.CollisionObjUtils; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.entity.types.debug.DebugVisualizerUtils; +import electrosphere.entity.types.item.ItemUtils; +import electrosphere.game.collision.PhysicsUtils; +import electrosphere.game.collision.collidable.Collidable; +import electrosphere.game.data.creature.type.CollidableTemplate; +import electrosphere.server.datacell.Realm; + +import org.joml.Matrix4f; +import org.joml.Quaterniond; +import org.joml.Quaternionf; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector4d; +import org.joml.Vector4f; + +/** + * + * @author amaterasu + */ +public class ServerCollidableTree implements BehaviorTree { + + Entity parent; + CollisionObject body; + Collidable collidable; + Quaternionf angularVelocity = new Quaternionf(0,0,0,0); + Vector4d cumulativeTorque = new Vector4d(0,0,0,0); + + boolean applyImpulses = true; + + static final float DELTA_T = 0.01f; + + public ServerCollidableTree(Entity e, Collidable collidable, CollisionObject body){ + parent = e; + this.collidable = collidable; + this.body = body; + } + + public ServerCollidableTree(Entity e, Collidable collidable, CollisionObject body, boolean applyImpulses){ + parent = e; + this.collidable = collidable; + this.body = body; + this.applyImpulses = applyImpulses; + } + + static int incrementer = 0; + + public void simulate(float deltaTime){ + Vector3d position = EntityUtils.getPosition(parent); + Quaternionf rotation = EntityUtils.getRotation(parent); + Matrix4f inverseInertiaTensor = CollisionObjUtils.getInverseInertiaTensor(parent); + Vector3d offsetVector = new Vector3d(); + Vector3d newPosition = new Vector3d(position); + javax.vecmath.Matrix4f bodyTransformMatrix; + //have we hit a terrain impulse? + boolean hitTerrain = false; + //handle impulses + for(Impulse impulse : collidable.getImpulses()){ +// collidable.getImpulses().remove(impulse); + Vector3d impulseForce = new Vector3d(impulse.getDirection()).mul(impulse.getForce()); + if(impulse.type.matches(Collidable.TYPE_TERRAIN)){ + hitTerrain = true; +// System.out.println("Impulse force: " + impulseForce); +// System.out.println("Position: " + position); + } + if(impulse.type.matches(Collidable.TYPE_ITEM)){ + if(parent.containsKey(EntityDataStrings.SERVER_GRAVITY_TREE)){ + ((ServerGravityTree)parent.getData(EntityDataStrings.SERVER_GRAVITY_TREE)).start(); + } + } + if(impulse.type.matches(Collidable.TYPE_CREATURE)){ +// System.out.println(System.currentTimeMillis() + " creature hit!"); + if(parent.containsKey(EntityDataStrings.SERVER_GRAVITY_TREE)){ + ((ServerGravityTree)parent.getData(EntityDataStrings.SERVER_GRAVITY_TREE)).start(); + } + } + if( + impulse.getCollisionPoint().length() > 0 && + !Double.isNaN(impulse.getCollisionPoint().x) && + !Double.isNaN(impulse.getCollisionPoint().y) && + !Double.isNaN(impulse.getCollisionPoint().z) && + !Double.isNaN(impulse.getDirection().x) && + !Double.isNaN(impulse.getDirection().y) && + !Double.isNaN(impulse.getDirection().z) && + ItemUtils.isItem(parent) + ){ + // Vector3d collisionPoint = new Vector3d(impulse.getCollisionPoint()).normalize(); + Vector3d collisionPoint = new Vector3d(impulse.getWorldPoint()).sub(position); + Vector3d forceDir = new Vector3d(impulse.getDirection()).normalize(); + Vector3d torqueVec = new Vector3d(collisionPoint).cross(forceDir).normalize(); + // double torqueMag = Math.abs(impulse.force); + double torqueMag = Math.sqrt(impulse.getCollisionPoint().length()) * impulse.getForce(); + if(impulse.getType().equals(Collidable.TYPE_TERRAIN)){ + torqueMag = torqueMag * 3; + } + torqueMag = torqueMag * 10; + // } else { + // torqueMag = 0; + // } + // if(impulse.type.matches(Collidable.TYPE_ITEM) && ItemUtils.isItem(parent)){ + // // System.out.println(rotation); + // if(impulse.collisionPoint.x < 0){ + // // System.out.println("Impulse collision point: " + impulse.getCollisionPoint() + " direction: " + impulse.getDirection() + " => " + new Vector3d(impulse.getCollisionPoint()).cross(impulse.getDirection())); + // cumulativeTorque.add(new Vector3d(impulse.getCollisionPoint()).cross(impulse.getDirection())); + // } + // } else { + // // angularVelocity.add(new Vector3d(impulse.getCollisionPoint()).cross(impulse.getDirection()),1.0); + // cumulativeTorque.add(new Vector3d(impulse.getCollisionPoint()).cross(impulse.getDirection())); + // } + if(impulse.type.matches(Collidable.TYPE_CREATURE)){ + // System.out.println("Impulse: " + impulse.getCollisionPoint() + " x " + impulse.getDirection() + " ->f " + impulse.force); + // incrementer++; + // if(incrementer > 5){ + // Globals.microSimulation.freeze(); + // } else if(incrementer <= 5){ + // // Globals.controlHandler.showMouse(); + // Vector3d pos = impulse.getWorldPoint(); + // // pos = new Vector3d(position).add(impulse.getCollisionPoint()).mul(1,0,1); + // DebugVisualizerUtils.spawnVectorVisualizer(impulse.getWorldPoint(), new Vector3d(torqueVec)); + // } + // System.out.println("Impulse: " + torqueVec + " " + torqueMag); + } + // if(CreatureUtils.isCreature(parent) && forceDir.y < 0.5){ + // System.out.println(collisionPoint + " x " + forceDir + " => " + torqueVec + " " + torqueMag); + // } + Quaternionf impulseRotation = new Quaternionf().rotationAxis((float)torqueMag * DELTA_T,new Vector3f((float)torqueVec.x,(float)torqueVec.y,(float)torqueVec.z)); + if(angularVelocity.lengthSquared() > 0.001){ + angularVelocity.mul(impulseRotation); + } else { + angularVelocity.set(impulseRotation); + } + // angularVelocity.add(new Vector4d((float)torqueVec.x,(float)torqueVec.y,(float)torqueVec.z,(float)torqueMag)); + // cumulativeTorque.add(new Vector4d((float)torqueVec.x,(float)torqueVec.y,(float)torqueVec.z,(float)torqueMag)); + } + offsetVector.add(impulseForce); + } + // if(ItemUtils.isItem(parent) && cumulativeTorque.w > 0.001){ + // System.out.println(cumulativeTorque); + // } + //friction + if(angularVelocity.lengthSquared() > 0.001){ + angularVelocity.slerp(new Quaternionf(0,0,0,1), 0.03f); + // angularVelocity.scale((float)(Math.sqrt(angularVelocity.lengthSquared()) * 0.9)); + // System.out.println(angularVelocity); + } + // if(cumulativeTorque.w > 0.001){ + // Vector4f holder = inverseInertiaTensor.transform(new Vector4f((float)cumulativeTorque.x,(float)cumulativeTorque.y,(float)cumulativeTorque.z,(float)cumulativeTorque.w)); + // cumulativeTorque = new Vector4d(holder.x,holder.y,holder.z,holder.w); + // angularVelocity = angularVelocity.add(cumulativeTorque).normalize(); + // cumulativeTorque.set(0,0,0,0); + // // Vector3d normalizedTorqueDir = new Vector3d(cumulativeTorque.x,cumulativeTorque.y,cumulativeTorque.z).normalize(); + // // double newMag = cumulativeTorque.w * 0.9; + // // cumulativeTorque.set(normalizedTorqueDir.x,normalizedTorqueDir.y,normalizedTorqueDir.z,newMag); + // } + if(angularVelocity.lengthSquared() > 0.001){ + // System.out.println("-" + rotation); + Quaternionf newRotation = new Quaternionf(rotation).mul(angularVelocity).normalize(); + // if(new Quaternionf(newRotation).add(new Quaternionf(rotation).conjugate()).lengthSquared() > 0.2){ + // newRotation.w = Math.copySign(newRotation.w, rotation.w); + // newRotation.x = Math.copySign(newRotation.x, rotation.x); + // newRotation.y = Math.copySign(newRotation.y, rotation.y); + // newRotation.z = Math.copySign(newRotation.z, rotation.z); + // } + rotation.set(newRotation); + // System.out.println("=" + rotation); + } + // if(inverseInertiaTensor != null && angularVelocity.w > 0.01){ + // // Vector4f angularMomentum = inverseInertiaTensor.transform(new Vector4f((float)cumulativeTorque.x,(float)cumulativeTorque.x,(float)cumulativeTorque.x,(float)cumulativeTorque.w)); + // // Quaternionf nextRotation = new Quaternionf(rotation).mul(new Quaternionf(angularMomentum.x,angularMomentum.y,angularMomentum.z,angularMomentum.w).scale(0.001f)).normalize(); + // // rotation = nextRotation; + // // rotation.mul(new Quaternionf((float)angularMomentum.x,(float)angularMomentum.y,(float)angularMomentum.z,(float)angularMomentum.w / 0.01f)); + // // if(ItemUtils.isItem(parent)){ + // // System.out.println("cumulative quat: " + cumulativeTorque); + // // } + // rotation.x = rotation.x + rotation.x * (float)(angularVelocity.x * angularVelocity.w) * 0.01f; + // rotation.y = rotation.y + rotation.y * (float)(angularVelocity.y * angularVelocity.w) * 0.01f; + // rotation.z = rotation.z + rotation.z * (float)(angularVelocity.z * angularVelocity.w) * 0.01f; + // rotation.w = 1; + // // rotation.w = rotation.w + rotation.w * (float)cumulativeTorque.w * 0.001f; + // rotation.normalize(); + // } + + //the reasoning here is that if we have something above something else and it's pushing it into the terrain, + //we should instead just not push into terrain and push along terrain + if(hitTerrain && offsetVector.y < 0){ + offsetVector.y = 0; + } + + //make sure we're in a valid (World bounds) position + if(applyImpulses){ + newPosition.add(offsetVector); + } + Realm parentRealm = Globals.realmManager.getEntityRealm(parent); + if(!parentRealm.getCollisionEngine().checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){ + newPosition = parentRealm.getCollisionEngine().suggestMovementPosition(Globals.commonWorldData, parent, newPosition); + } + position.set(newPosition); + + //update collision engine of this thing's position + CollidableTemplate template = (CollidableTemplate)parent.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE); + bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(new Vector3f((float)position.x + template.getOffsetX(),(float)position.y + template.getOffsetY(),(float)position.z + template.getOffsetZ())),1.0f); + body.setWorldTransform(new electrosphere.linearmath.Transform(bodyTransformMatrix)); + +// bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(new Vector3f((float)newPosition.x,(float)newPosition.y,(float)newPosition.z)),1.0f); +// body.setWorldTransform(new electrosphere.linearmath.Transform(bodyTransformMatrix)); + + } + + + public void setCollisionObject(CollisionObject body, Collidable collidable){ + this.body = body; + this.collidable = collidable; + } + + public float getAngularVelocityMagnitude(){ + return angularVelocity.lengthSquared(); + } + + public static boolean hasServerCollidableTree(Entity e){ + return e.containsKey(EntityDataStrings.SERVER_COLLIDABLE_TREE); + } + + public static ServerCollidableTree getServerCollidableTree(Entity e){ + return (ServerCollidableTree)e.getData(EntityDataStrings.SERVER_COLLIDABLE_TREE); + } + + +} diff --git a/src/main/java/electrosphere/entity/state/equip/EquipState.java b/src/main/java/electrosphere/entity/state/equip/EquipState.java index 380126e1..f937a94e 100644 --- a/src/main/java/electrosphere/entity/state/equip/EquipState.java +++ b/src/main/java/electrosphere/entity/state/equip/EquipState.java @@ -31,7 +31,10 @@ import electrosphere.net.server.player.Player; import electrosphere.net.server.protocol.InventoryProtocol; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.ActorMeshMask; +import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.datacell.utils.DataCellSearchUtils; +import electrosphere.server.datacell.utils.ServerEntityTagUtils; /** * @@ -69,7 +72,7 @@ public class EquipState { serverAttemptEquip(toEquip, point); } else { String pointName = point.getEquipPointId(); - int serverSideID = Globals.entityManager.mapClientToServerId(toEquip.getId()); + int serverSideID = Globals.clientSceneWrapper.mapClientToServerId(toEquip.getId()); NetworkMessage requestPickupMessage = InventoryMessage.constructclientRequestEquipItemMessage(pointName, serverSideID); Globals.clientConnection.queueOutgoingMessage(requestPickupMessage); } @@ -86,7 +89,8 @@ public class EquipState { if(!hasEquipped && targetIsItem && itemIsInPointWhitelist){ //hydrate inventory item String itemType = ItemUtils.getType(inInventoryEntity); - Entity inWorldItem = ItemUtils.spawnBasicItem(itemType); + Realm realm = Globals.realmManager.getEntityRealm(parent); + Entity inWorldItem = ItemUtils.serverSpawnBasicItem(realm,new Vector3d(0,0,0),itemType); //bind in world with in inventory ItemUtils.setRealWorldEntity(inInventoryEntity, inWorldItem); @@ -110,29 +114,31 @@ public class EquipState { meshMask.queueMesh(modelName, toDraw); } //attach to parent bone - AttachUtils.attachEntityToEntityAtBone(parent, inWorldItem, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); + AttachUtils.serverAttachEntityToEntityAtBone(parent, inWorldItem, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); //make uncollidable if(inWorldItem.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY) && inWorldItem.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){ CollisionObject rigidBody = (CollisionObject)inWorldItem.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); - Globals.collisionEngine.deregisterPhysicsObject(rigidBody); + Realm inWorldRealm = Globals.realmManager.getEntityRealm(inWorldItem); + inWorldRealm.getCollisionEngine().deregisterPhysicsObject(rigidBody); } //hide toEquip actor EntityUtils.setDraw(inWorldItem, false); //make untargetable - Globals.entityManager.removeEntityFromTag(inWorldItem, EntityTags.TARGETABLE); + ServerEntityTagUtils.removeTagFromEntity(inWorldItem, EntityTags.TARGETABLE); break; } } } else { //since we're not replacing meshes we must be attaching to a bone equipMap.put(point.getEquipPointId(),inWorldItem); - AttachUtils.attachEntityToEntityAtBone(parent, inWorldItem, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); + AttachUtils.serverAttachEntityToEntityAtBone(parent, inWorldItem, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); if(inWorldItem.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY) && inWorldItem.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){ CollisionObject rigidBody = (CollisionObject)inWorldItem.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); - Globals.collisionEngine.deregisterPhysicsObject(rigidBody); + Realm inWorldRealm = Globals.realmManager.getEntityRealm(inWorldItem); + inWorldRealm.getCollisionEngine().deregisterPhysicsObject(rigidBody); } - Globals.entityManager.removeEntityFromTag(inWorldItem, EntityTags.TARGETABLE); - GravityUtils.attemptDeactivateGravity(inWorldItem); + ServerEntityTagUtils.removeTagFromEntity(inWorldItem, EntityTags.TARGETABLE); + GravityUtils.serverAttemptDeactivateGravity(inWorldItem); } //we need to send two packets //1) Remove item from original inventory @@ -166,7 +172,7 @@ public class EquipState { } //get the chunk the equipper is in, and broadcast to that chunk that they equipped the item //get datacell - ServerDataCell dataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(parent)); + ServerDataCell dataCell = DataCellSearchUtils.getEntityDataCell(parent); //broadcast attach entity int equipperId = parent.getId(); String equipPointId = point.getEquipPointId(); @@ -206,29 +212,29 @@ public class EquipState { meshMask.queueMesh(modelName, toDraw); } //attach to parent bone - AttachUtils.attachEntityToEntityAtBone(parent, toEquip, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); + AttachUtils.clientAttachEntityToEntityAtBone(parent, toEquip, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); //make uncollidable if(toEquip.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY) && toEquip.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){ CollisionObject rigidBody = (CollisionObject)toEquip.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); - Globals.collisionEngine.deregisterPhysicsObject(rigidBody); + Globals.clientSceneWrapper.getCollisionEngine().deregisterPhysicsObject(rigidBody); } //hide toEquip actor EntityUtils.setDraw(toEquip, false); //make untargetable - Globals.entityManager.removeEntityFromTag(toEquip, EntityTags.TARGETABLE); + Globals.clientSceneWrapper.getScene().removeEntityFromTag(toEquip, EntityTags.TARGETABLE); break; } } } else { //since we're not replacing meshes we must be attaching to a bone equipMap.put(point.getEquipPointId(),toEquip); - AttachUtils.attachEntityToEntityAtBone(parent, toEquip, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); + AttachUtils.clientAttachEntityToEntityAtBone(parent, toEquip, point.getBone(), AttachUtils.getEquipPointRotationOffset(point.getOffsetRotation())); if(toEquip.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY) && toEquip.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){ CollisionObject rigidBody = (CollisionObject)toEquip.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); - Globals.collisionEngine.deregisterPhysicsObject(rigidBody); + Globals.clientSceneWrapper.getCollisionEngine().deregisterPhysicsObject(rigidBody); } - Globals.entityManager.removeEntityFromTag(toEquip, EntityTags.TARGETABLE); - GravityUtils.attemptDeactivateGravity(toEquip); + Globals.clientSceneWrapper.getScene().removeEntityFromTag(toEquip, EntityTags.TARGETABLE); + GravityUtils.clientAttemptDeactivateGravity(toEquip); } } @@ -356,10 +362,10 @@ public class EquipState { equipInventory.removeItemSlot(pointId); naturalInventory.addItem(ejectedItem); //destroy in world item - transformUnequipPoint(pointId); + serverTransformUnequipPoint(pointId); //tell all clients to unequip the world item //get datacell - ServerDataCell dataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(parent)); + ServerDataCell dataCell = DataCellSearchUtils.getEntityDataCell(parent); //broadcast attach entity NetworkMessage unequipMessage = InventoryMessage.constructserverCommandUnequipItemMessage(parent.getId(), pointId); //actually send the packet @@ -388,7 +394,19 @@ public class EquipState { // inventory.addItem(item); } - public void transformUnequipPoint(String pointId){ + public void clientTransformUnequipPoint(String pointId){ + Entity equipped = equipMap.remove(pointId); + if(equipped != null){ + boolean targetHasWhitelist = ItemUtils.hasEquipList(equipped); + if(targetHasWhitelist){ + } else { + AttachUtils.clientDetatchEntityFromEntityAtBone(parent, equipped); + EntityUtils.cleanUpEntity(equipped); + } + } + } + + public void serverTransformUnequipPoint(String pointId){ Entity equipped = equipMap.remove(pointId); if(equipped != null){ boolean targetHasWhitelist = ItemUtils.hasEquipList(equipped); @@ -426,8 +444,8 @@ public class EquipState { // } // } } else { - AttachUtils.detatchEntityFromEntityAtBone(parent, equipped); - EntityUtils.cleanUpDrawableEntity(equipped); + AttachUtils.serverDetatchEntityFromEntityAtBone(parent, equipped); + EntityUtils.cleanUpEntity(equipped); } } } diff --git a/src/main/java/electrosphere/entity/state/gravity/GravityTree.java b/src/main/java/electrosphere/entity/state/gravity/GravityTree.java index 0f85ff8c..3db28fd6 100644 --- a/src/main/java/electrosphere/entity/state/gravity/GravityTree.java +++ b/src/main/java/electrosphere/entity/state/gravity/GravityTree.java @@ -12,7 +12,7 @@ import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.BehaviorTree; -import electrosphere.entity.state.collidable.CollidableTree; +import electrosphere.entity.state.collidable.ClientCollidableTree; import electrosphere.entity.state.collidable.Impulse; import electrosphere.entity.state.movement.FallTree; import electrosphere.entity.state.movement.JumpTree; @@ -91,9 +91,9 @@ public class GravityTree implements BehaviorTree { Quaternionf rotation = EntityUtils.getRotation(parent); Vector3f newPosition; javax.vecmath.Matrix4f bodyTransformMatrix; - CollidableTree collidableTree = null; - if(CollidableTree.hasCollidableTree(parent)){ - collidableTree = CollidableTree.getCollidableTree(parent); + ClientCollidableTree collidableTree = null; + if(ClientCollidableTree.hasClientCollidableTree(parent)){ + collidableTree = ClientCollidableTree.getClientCollidableTree(parent); } //parse attached network messages @@ -134,7 +134,7 @@ public class GravityTree implements BehaviorTree { // position.set(new Vector3d(position.x,Globals.commonWorldData.getElevationAtPoint(position) + 0.0001f,position.z)); } JumpTree jumpTree; - if((jumpTree = JumpTree.getJumpTree(parent))!=null){ + if((jumpTree = JumpTree.getClientJumpTree(parent))!=null){ jumpTree.land(); } FallTree fallTree; @@ -162,7 +162,7 @@ public class GravityTree implements BehaviorTree { } float gravityDif = gravityVelocity * (float)Math.pow(1.0f - linearDamping,deltaTime * 2); Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z); - float hitFraction = Globals.collisionEngine.sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z)); + float hitFraction = Globals.clientSceneWrapper.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z)); // if(hitFraction >= 0){ // collidable.addImpulse(new Impulse(new Vector3d(0,-1,0),gravityDif * hitFraction,"gravity")); // position.set(new Vector3d(position.x,position.y - gravityDif * hitFraction,position.z)); diff --git a/src/main/java/electrosphere/entity/state/gravity/GravityUtils.java b/src/main/java/electrosphere/entity/state/gravity/GravityUtils.java index 84906c5f..11ba9aa4 100644 --- a/src/main/java/electrosphere/entity/state/gravity/GravityUtils.java +++ b/src/main/java/electrosphere/entity/state/gravity/GravityUtils.java @@ -5,16 +5,30 @@ import electrosphere.entity.EntityDataStrings; public class GravityUtils { - public static void attemptActivateGravity(Entity target){ + public static void clientAttemptActivateGravity(Entity target){ if(target.containsKey(EntityDataStrings.GRAVITY_ENTITY)){ - GravityTree tree = (GravityTree)target.getData(EntityDataStrings.GRAVITY_TREE); + GravityTree tree = (GravityTree)target.getData(EntityDataStrings.CLIENT_GRAVITY_TREE); tree.start(); } } - public static void attemptDeactivateGravity(Entity target){ + public static void serverAttemptActivateGravity(Entity target){ if(target.containsKey(EntityDataStrings.GRAVITY_ENTITY)){ - GravityTree tree = (GravityTree)target.getData(EntityDataStrings.GRAVITY_TREE); + ServerGravityTree tree = (ServerGravityTree)target.getData(EntityDataStrings.SERVER_GRAVITY_TREE); + tree.start(); + } + } + + public static void clientAttemptDeactivateGravity(Entity target){ + if(target.containsKey(EntityDataStrings.GRAVITY_ENTITY)){ + GravityTree tree = (GravityTree)target.getData(EntityDataStrings.CLIENT_GRAVITY_TREE); + tree.stop(); + } + } + + public static void serverAttemptDeactivateGravity(Entity target){ + if(target.containsKey(EntityDataStrings.GRAVITY_ENTITY)){ + ServerGravityTree tree = (ServerGravityTree)target.getData(EntityDataStrings.SERVER_GRAVITY_TREE); tree.stop(); } } diff --git a/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java b/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java new file mode 100644 index 00000000..ab93f2ab --- /dev/null +++ b/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java @@ -0,0 +1,238 @@ +package electrosphere.entity.state.gravity; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import org.joml.Quaternionf; +import org.joml.Vector3d; +import org.joml.Vector3f; + +import electrosphere.collision.dispatch.CollisionObject; +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.collidable.ClientCollidableTree; +import electrosphere.entity.state.collidable.Impulse; +import electrosphere.entity.state.collidable.ServerCollidableTree; +import electrosphere.entity.state.movement.FallTree; +import electrosphere.entity.state.movement.JumpTree; +import electrosphere.entity.state.movement.ServerFallTree; +import electrosphere.entity.state.movement.ServerJumpTree; +import electrosphere.game.collision.collidable.Collidable; +import electrosphere.net.parser.net.message.EntityMessage; +import electrosphere.server.datacell.Realm; + +/** + * + * @author amaterasu + */ +public class ServerGravityTree implements BehaviorTree { + + public static enum GravityTreeState { + ACTIVE, + NOT_ACTIVE, + } + + GravityTreeState state; + + Entity parent; + + int frameCurrent = 0; + int fallFrame = 1; + + float gravityVelocity = 0; + float gravityAccel = 0.0007f; + + CollisionObject body; + Collidable collidable; + + List networkMessageQueue = new CopyOnWriteArrayList(); + + public ServerGravityTree(Entity e, Collidable collidable, CollisionObject body, int fallFrame){ + state = GravityTreeState.ACTIVE; + parent = e; + this.body = body; + this.collidable = collidable; + this.fallFrame = fallFrame; + } + +// public void setCollisionObject(CollisionObject body, Collidable collidable){ +// this.body = body; +// this.collidable = collidable; +// } + + public GravityTreeState getState(){ + return state; + } + + public void start(){ + //TODO: check if can start moving + state = GravityTreeState.ACTIVE; + if(state == GravityTreeState.NOT_ACTIVE){ + frameCurrent = 0; + } + } + + public void interrupt(){ + state = GravityTreeState.NOT_ACTIVE; + } + + public void stop(){ + state = GravityTreeState.NOT_ACTIVE; + } + + static final float gravityConstant = 0.2f; + static final float linearDamping = 0.1f; + + public void simulate(float deltaTime){ +// float velocity = CreatureUtils.getVelocity(parent); +// float acceleration = CreatureUtils.getAcceleration(parent); +// float maxNaturalVelocity = CreatureUtils.getMaxNaturalVelocity(parent); +// Actor entityActor = EntityUtils.getActor(parent); + Vector3d position = EntityUtils.getPosition(parent); +// Vector3f movementVector = CreatureUtils.getMovementVector(parent); + Quaternionf rotation = EntityUtils.getRotation(parent); + Vector3f newPosition; + javax.vecmath.Matrix4f bodyTransformMatrix; + ServerCollidableTree collidableTree = null; + if(ServerCollidableTree.hasServerCollidableTree(parent)){ + collidableTree = ServerCollidableTree.getServerCollidableTree(parent); + } + + //parse attached network messages +// for(EntityMessage message : networkMessageQueue){ +// networkMessageQueue.remove(message); +//// System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ()); +// switch(message.getMessageSubtype()){ +// case ATTACKUPDATE: +// switch(message.gettreeState()){ +// case 0: +// state = IdleTreeState.IDLE; +// break; +// case 1: +// state = IdleTreeState.NOT_IDLE; +// break; +// } +// EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); +// CreatureUtils.setMovementVector(parent, new Vector3f(message.getrotationX(),message.getrotationY(),message.getrotationZ())); +// break; +// } +// } + + //Basically if we're still spinning keep applying gravity + boolean angularVelocityLow = true; + if(collidableTree != null){ + if(collidableTree.getAngularVelocityMagnitude() > 0.0001){ + angularVelocityLow = false; + } + } + + + //state machine + switch(state){ + case ACTIVE: + if(hadGroundCollision()){ + state = GravityTreeState.NOT_ACTIVE; + if(!hadStructureCollision()){ +// position.set(new Vector3d(position.x,Globals.commonWorldData.getElevationAtPoint(position) + 0.0001f,position.z)); + } + ServerJumpTree jumpTree; + if((jumpTree = ServerJumpTree.getServerJumpTree(parent))!=null){ + jumpTree.land(); + } + ServerFallTree fallTree; + if((fallTree = ServerFallTree.getFallTree(parent))!=null){ + fallTree.land(); + } + frameCurrent = 0; + gravityVelocity = 0; + } else { + //animation nonsense + frameCurrent++; + if(frameCurrent == fallFrame){ + ServerFallTree fallTree; + if((fallTree = ServerFallTree.getFallTree(parent))!=null){ + fallTree.start(); + } + } + + //actual gravity calculations + if(gravityVelocity < gravityConstant){ + gravityVelocity = gravityVelocity + gravityAccel; + } + if(gravityVelocity > gravityConstant){ + gravityVelocity = gravityConstant; + } + float gravityDif = gravityVelocity * (float)Math.pow(1.0f - linearDamping,deltaTime * 2); + Vector3d newGravityPos = new Vector3d(position.x,position.y - gravityDif,position.z); + Realm parentRealm = Globals.realmManager.getEntityRealm(parent); + float hitFraction = parentRealm.getCollisionEngine().sweepTest(body, new Vector3f((float)position.x,(float)position.y,(float)position.z), new Vector3f((float)newGravityPos.x,(float)newGravityPos.y,(float)newGravityPos.z)); +// if(hitFraction >= 0){ +// collidable.addImpulse(new Impulse(new Vector3d(0,-1,0),gravityDif * hitFraction,"gravity")); +// position.set(new Vector3d(position.x,position.y - gravityDif * hitFraction,position.z)); +// } else { +// position.set(new Vector3d(position.x,position.y - gravityDif,position.z)); +// } + if(hitFraction < 0){ + hitFraction = 1; + } + collidable.addImpulse(new Impulse(new Vector3d(0,-1,0), new Vector3d(0,0,0), new Vector3d(position), gravityDif * hitFraction,"gravity")); +// System.out.println(hitFraction); +// bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(new Vector3f((float)position.x,(float)position.y,(float)position.z)),1.0f); +// body.setWorldTransform(new electrosphere.linearmath.Transform(bodyTransformMatrix)); + } + break; + case NOT_ACTIVE: + if(hadEntityCollision()){ + start(); + } + //nothing here atm + //eventually want to check if need to re-activate somehow + break; + } + } + + public void addNetworkMessage(EntityMessage networkMessage) { + networkMessageQueue.add(networkMessage); + } + + public boolean hadStructureCollision(){ + boolean rVal = false; + for(Impulse impulse : collidable.getImpulses()){ + if(impulse.getType().equals(Collidable.TYPE_STRUCTURE)){ + rVal = true; + break; + } + } + return rVal; + } + + public boolean hadGroundCollision(){ + boolean rVal = false; + for(Impulse impulse : collidable.getImpulses()){ + if(impulse.getType().equals(Collidable.TYPE_TERRAIN)){ + rVal = true; + break; + } else if( + impulse.getType().equals(Collidable.TYPE_STRUCTURE) && + new Vector3d(impulse.getDirection()).normalize().y > 0.7 + ){ + rVal = true; + } + } + return rVal; + } + + public boolean hadEntityCollision(){ + boolean rVal = false; + for(Impulse impulse : collidable.getImpulses()){ + if(impulse.getType().equals(Collidable.TYPE_CREATURE)){ + rVal = true; + break; + } + } + return rVal; + } + +} diff --git a/src/main/java/electrosphere/entity/state/IdleTree.java b/src/main/java/electrosphere/entity/state/idle/IdleTree.java similarity index 93% rename from src/main/java/electrosphere/entity/state/IdleTree.java rename to src/main/java/electrosphere/entity/state/idle/IdleTree.java index f684b9e4..b0bb34ba 100644 --- a/src/main/java/electrosphere/entity/state/IdleTree.java +++ b/src/main/java/electrosphere/entity/state/idle/IdleTree.java @@ -1,5 +1,8 @@ -package electrosphere.entity.state; +package electrosphere.entity.state.idle; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.BehaviorTreeAnnotation; +import electrosphere.entity.state.SyncedField; import electrosphere.entity.state.attack.AttackTree; import electrosphere.entity.state.attack.AttackTree.AttackTreeState; import electrosphere.entity.state.movement.AirplaneMovementTree; @@ -64,10 +67,10 @@ public class IdleTree { boolean movementTreeIsIdle = movementTreeIsIdle(); - boolean hasAttackTree = parent.containsKey(EntityDataStrings.ATTACK_TREE); + boolean hasAttackTree = parent.containsKey(EntityDataStrings.CLIENT_ATTACK_TREE); AttackTree attackTree = null; if(hasAttackTree){ - attackTree = CreatureUtils.getAttackTree(parent); + attackTree = CreatureUtils.clientGetAttackTree(parent); } //parse attached network messages @@ -151,9 +154,9 @@ public class IdleTree { boolean movementTreeIsIdle(){ boolean rVal = false; - boolean hasMovementTree = parent.containsKey(EntityDataStrings.DATA_STRING_MOVEMENT_BT); + boolean hasMovementTree = parent.containsKey(EntityDataStrings.CLIENT_MOVEMENT_BT); if(hasMovementTree){ - BehaviorTree movementTree = CreatureUtils.getEntityMovementTree(parent); + BehaviorTree movementTree = CreatureUtils.clientGetEntityMovementTree(parent); if(movementTree instanceof GroundMovementTree){ if(((GroundMovementTree)movementTree).getState() == MovementTreeState.IDLE){ rVal = true; diff --git a/src/main/java/electrosphere/entity/state/idle/ServerIdleTree.java b/src/main/java/electrosphere/entity/state/idle/ServerIdleTree.java new file mode 100644 index 00000000..a7461ade --- /dev/null +++ b/src/main/java/electrosphere/entity/state/idle/ServerIdleTree.java @@ -0,0 +1,175 @@ +package electrosphere.entity.state.idle; + +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.BehaviorTreeAnnotation; +import electrosphere.entity.state.SyncedField; +import electrosphere.entity.state.attack.ServerAttackTree; +import electrosphere.entity.state.attack.ServerAttackTree.AttackTreeState; +import electrosphere.entity.state.movement.AirplaneMovementTree; +import electrosphere.entity.state.movement.ServerGroundMovementTree; +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.movement.ServerGroundMovementTree.MovementTreeState; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.net.parser.net.message.EntityMessage; +import electrosphere.renderer.actor.Actor; +import electrosphere.renderer.anim.Animation; +import java.util.concurrent.CopyOnWriteArrayList; +import org.joml.Vector3d; + + +@BehaviorTreeAnnotation(name="idle") +public class ServerIdleTree { + + public static enum IdleTreeState { + IDLE, + NOT_IDLE, + } + + @SyncedField(isEnum = true) + IdleTreeState state; + + Entity parent; + + CopyOnWriteArrayList networkMessageQueue = new CopyOnWriteArrayList(); + + int frameCurrent; + + int maxFrame = 60; + + public ServerIdleTree(Entity e){ + state = IdleTreeState.IDLE; + parent = e; + } + + public IdleTreeState getState(){ + return state; +} + + public void start(){ + //TODO: check if can start moving + state = IdleTreeState.IDLE; + frameCurrent = 0; + } + + public void interrupt(){ + state = IdleTreeState.NOT_IDLE; + } + + public void stop(){ + state = IdleTreeState.NOT_IDLE; + } + + public void simulate(float deltaTime){ + Actor entityActor = EntityUtils.getActor(parent); + + boolean movementTreeIsIdle = movementTreeIsIdle(); + + boolean hasAttackTree = parent.containsKey(EntityDataStrings.SERVER_ATTACK_TREE); + ServerAttackTree attackTree = null; + if(hasAttackTree){ + attackTree = CreatureUtils.serverGetAttackTree(parent); + } + + //parse attached network messages + for(EntityMessage message : networkMessageQueue){ + networkMessageQueue.remove(message); +// System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ()); + switch(message.getMessageSubtype()){ + case ATTACKUPDATE: + switch(message.gettreeState()){ + case 0: + state = IdleTreeState.IDLE; + break; + case 1: + state = IdleTreeState.NOT_IDLE; + break; + } + EntityUtils.getPosition(parent).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); + CreatureUtils.setFacingVector(parent, new Vector3d(message.getrotationX(),message.getrotationY(),message.getrotationZ())); + break; + case ATTACHENTITYTOENTITY: + case CREATE: + case DESTROY: + case MOVE: + case MOVEUPDATE: + case SETBEHAVIORTREE: + case SETFACING: + case SETPOSITION: + case SETPROPERTY: + case SPAWNCREATURE: + case SPAWNITEM: + case KILL: + //silently ignore + break; + } + } + + boolean isIdle; + + //state machine + switch(state){ + case IDLE: + if(entityActor != null){ + if( + (!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(Animation.ANIMATION_IDLE_1)) && + (Globals.assetManager.fetchModel(entityActor.getModelPath()) != null && Globals.assetManager.fetchModel(entityActor.getModelPath()).getAnimation(Animation.ANIMATION_IDLE_1) != null) + + ){ + entityActor.playAnimation(Animation.ANIMATION_IDLE_1,3); + entityActor.incrementAnimationTime(0.0001); + } + } + isIdle = true; + if(!movementTreeIsIdle){ + isIdle = false; + } + if(hasAttackTree){ + if(attackTree.getState() != AttackTreeState.IDLE){ + isIdle = false; + } + } + if(!isIdle){ + state = IdleTreeState.NOT_IDLE; + } + break; + case NOT_IDLE: + isIdle = true; + if(!movementTreeIsIdle){ + isIdle = false; + } + if(hasAttackTree){ + if(attackTree.getState() != AttackTreeState.IDLE){ + isIdle = false; + } + } + if(isIdle){ + state = IdleTreeState.IDLE; + } + break; + } + } + + boolean movementTreeIsIdle(){ + boolean rVal = false; + boolean hasMovementTree = parent.containsKey(EntityDataStrings.SERVER_MOVEMENT_BT); + if(hasMovementTree){ + BehaviorTree movementTree = CreatureUtils.serverGetEntityMovementTree(parent); + if(movementTree instanceof ServerGroundMovementTree){ + if(((ServerGroundMovementTree)movementTree).getState() == MovementTreeState.IDLE){ + rVal = true; + } + } else if(movementTree instanceof AirplaneMovementTree){ + rVal = false; + } + } + return rVal; + } + + public void addNetworkMessage(EntityMessage networkMessage) { + networkMessageQueue.add(networkMessage); + } + +} diff --git a/src/main/java/electrosphere/entity/state/inventory/InventoryState.java b/src/main/java/electrosphere/entity/state/inventory/InventoryState.java index 55f8c032..84f20bbd 100644 --- a/src/main/java/electrosphere/entity/state/inventory/InventoryState.java +++ b/src/main/java/electrosphere/entity/state/inventory/InventoryState.java @@ -4,6 +4,7 @@ import java.util.concurrent.CopyOnWriteArrayList; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; import electrosphere.entity.state.BehaviorTree; import electrosphere.entity.state.equip.EquipState; import electrosphere.entity.types.item.ItemUtils; @@ -12,6 +13,8 @@ import electrosphere.menu.WindowStrings; import electrosphere.menu.WindowUtils; import electrosphere.net.parser.net.message.InventoryMessage; import electrosphere.net.server.protocol.InventoryProtocol; +import electrosphere.server.datacell.utils.EntityLookupUtils; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; /** * Principally used to handle network messages related to inventory and thread synchronization @@ -26,127 +29,86 @@ public class InventoryState implements BehaviorTree { } - public static InventoryState createInventoryState(Entity parent){ + public static InventoryState clientCreateInventoryState(Entity parent){ InventoryState rVal = new InventoryState(); rVal.parent = parent; - Globals.entityManager.registerBehaviorTree(rVal); + Globals.clientSceneWrapper.getScene().registerBehaviorTree(rVal); return rVal; } @Override public void simulate(float deltaTime) { - if(Globals.RUN_SERVER){ - for(InventoryMessage message : networkMessageQueue){ - networkMessageQueue.remove(message); - switch(message.getMessageSubtype()){ - case ADDITEMTOINVENTORY: - InventoryUtils.attemptStoreItem(parent, Globals.entityManager.getEntityFromId(message.getentityId())); - break; - case REMOVEITEMFROMINVENTORY: - InventoryUtils.attemptEjectItem(parent, Globals.entityManager.getEntityFromId(message.getentityId())); - break; - case CLIENTREQUESTEQUIPITEM:{ - //item to equip - Entity target = Globals.entityManager.getEntityFromId(message.getentityId()); - //perform transform if it makes sense - if(InventoryUtils.hasEquipInventory(parent) && InventoryUtils.hasNaturalInventory(parent) && EquipState.hasEquipState(parent)){ - EquipState equipState = EquipState.getEquipState(parent); - EquipPoint point = equipState.getEquipPoint(message.getequipPointId()); - equipState.commandAttemptEquip(target, point); - } + for(InventoryMessage message : networkMessageQueue){ + networkMessageQueue.remove(message); + switch(message.getMessageSubtype()){ + case ADDITEMTOINVENTORY: + //the ID we get is of the in-inventory item + Entity inInventorySpawnedItem = InventoryUtils.clientConstructInInventoryItem(parent,message.getitemTemplate()); + //map id + if(inInventorySpawnedItem != null){ + Globals.clientSceneWrapper.mapIdToId(inInventorySpawnedItem.getId(), message.getentityId()); } + //attempt re-render ui + WindowUtils.attemptRedrawInventoryWindows(); break; - case CLIENTREQUESTUNEQUIPITEM:{ - //make sure can unequip - if(InventoryUtils.hasEquipInventory(parent) && InventoryUtils.hasNaturalInventory(parent) && EquipState.hasEquipState(parent)){ - EquipState equipState = EquipState.getEquipState(parent); - EquipPoint point = equipState.getEquipPoint(message.getequipPointId()); - if(equipState.hasEquippedAtPoint(message.getequipPointId())){ - equipState.commandAttemptUnequip(message.getequipPointId()); - //tell player - } + case REMOVEITEMFROMINVENTORY: + InventoryUtils.removeItemFromInventories(parent, Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId())); + //attempt re-render ui + WindowUtils.attemptRedrawInventoryWindows(); + break; + case SERVERCOMMANDMOVEITEMCONTAINER: { + //this is a command to switch an item from one inventory to another (ie equip->natural or vice-versa) + switch(message.getcontainerType()){ + case InventoryProtocol.INVENTORY_TYPE_EQUIP: + Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()); + boolean isInventoryItem = ItemUtils.itemIsInInventory(target); + boolean parentHasNaturalInventory = InventoryUtils.hasNaturalInventory(parent); + boolean parentHasEquipInventory = InventoryUtils.hasEquipInventory(parent); + String equipPointId = message.getequipPointId(); + //check that we can do the transform + if(isInventoryItem && parentHasEquipInventory && parentHasNaturalInventory){ + //switch containers + UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent); + RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent); + naturalInventory.removeItem(target); + equipInventory.addItem(equipPointId, target); } + break; + case InventoryProtocol.INVENTORY_TYPE_NATURAL: + target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityId()); + isInventoryItem = ItemUtils.itemIsInInventory(target); + parentHasNaturalInventory = InventoryUtils.hasNaturalInventory(parent); + parentHasEquipInventory = InventoryUtils.hasEquipInventory(parent); + equipPointId = message.getequipPointId(); + //check that we can do the transform + if(isInventoryItem && parentHasEquipInventory && parentHasNaturalInventory){ + //switch containers + UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent); + RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent); + naturalInventory.addItem(target); + equipInventory.removeItemSlot(equipPointId); + } + break; } - break; - case SERVERCOMMANDUNEQUIPITEM: - case SERVERCOMMANDEQUIPITEM: - case SERVERCOMMANDMOVEITEMCONTAINER: - break; + //once we've switched the items around, redraw the inventory to reflect the updated contents + WindowUtils.attemptRedrawInventoryWindows(); } - } - } else { - for(InventoryMessage message : networkMessageQueue){ - networkMessageQueue.remove(message); - switch(message.getMessageSubtype()){ - case ADDITEMTOINVENTORY: - //the ID we get is of the in-inventory item - Entity inInventorySpawnedItem = InventoryUtils.constructInInventoryItem(parent,message.getitemTemplate()); - //map id - if(inInventorySpawnedItem != null){ - Globals.entityManager.mapIdToId(inInventorySpawnedItem.getId(), message.getentityId()); - } - //attempt re-render ui - WindowUtils.attemptRedrawInventoryWindows(); - break; - case REMOVEITEMFROMINVENTORY: - InventoryUtils.removeItemFromInventories(parent, Globals.entityManager.getEntityFromServerId(message.getentityId())); - //attempt re-render ui - WindowUtils.attemptRedrawInventoryWindows(); - break; - case SERVERCOMMANDMOVEITEMCONTAINER: { - //this is a command to switch an item from one inventory to another (ie equip->natural or vice-versa) - switch(message.getcontainerType()){ - case InventoryProtocol.INVENTORY_TYPE_EQUIP: - Entity target = Globals.entityManager.getEntityFromId(Globals.entityManager.mapServerToClientId(message.getentityId())); - boolean isInventoryItem = ItemUtils.itemIsInInventory(target); - boolean parentHasNaturalInventory = InventoryUtils.hasNaturalInventory(parent); - boolean parentHasEquipInventory = InventoryUtils.hasEquipInventory(parent); - String equipPointId = message.getequipPointId(); - //check that we can do the transform - if(isInventoryItem && parentHasEquipInventory && parentHasNaturalInventory){ - //switch containers - UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent); - RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent); - naturalInventory.removeItem(target); - equipInventory.addItem(equipPointId, target); - } - break; - case InventoryProtocol.INVENTORY_TYPE_NATURAL: - target = Globals.entityManager.getEntityFromId(Globals.entityManager.mapServerToClientId(message.getentityId())); - isInventoryItem = ItemUtils.itemIsInInventory(target); - parentHasNaturalInventory = InventoryUtils.hasNaturalInventory(parent); - parentHasEquipInventory = InventoryUtils.hasEquipInventory(parent); - equipPointId = message.getequipPointId(); - //check that we can do the transform - if(isInventoryItem && parentHasEquipInventory && parentHasNaturalInventory){ - //switch containers - UnrelationalInventoryState naturalInventory = InventoryUtils.getNaturalInventory(parent); - RelationalInventoryState equipInventory = InventoryUtils.getEquipInventory(parent); - naturalInventory.addItem(target); - equipInventory.removeItemSlot(equipPointId); - } - break; - } - //once we've switched the items around, redraw the inventory to reflect the updated contents - WindowUtils.attemptRedrawInventoryWindows(); + break; + case SERVERCOMMANDUNEQUIPITEM: { + if(Globals.playerEntity != null && EquipState.hasEquipState(Globals.playerEntity)){ + //unequip the item + EquipState equipState = EquipState.getEquipState(Globals.playerEntity); + Entity entityInSlot = equipState.getEquippedItemAtPoint(message.getequipPointId()); + equipState.clientTransformUnequipPoint(message.getequipPointId()); + //destroy the in-world manifestation of said item + EntityUtils.cleanUpEntity(entityInSlot); } - break; - case SERVERCOMMANDUNEQUIPITEM: { - if(Globals.playerEntity != null && EquipState.hasEquipState(Globals.playerEntity)){ - //unequip the item - EquipState equipState = EquipState.getEquipState(Globals.playerEntity); - Entity entityInSlot = equipState.getEquippedItemAtPoint(message.getequipPointId()); - equipState.transformUnequipPoint(message.getequipPointId()); - //destroy the in-world manifestation of said item - Globals.entityManager.deregisterEntity(entityInSlot); - } - } - break; - case CLIENTREQUESTEQUIPITEM: - case CLIENTREQUESTUNEQUIPITEM: - case SERVERCOMMANDEQUIPITEM: - break; } + break; + case CLIENTREQUESTEQUIPITEM: + case CLIENTREQUESTUNEQUIPITEM: + case SERVERCOMMANDEQUIPITEM: + break; } } } diff --git a/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java b/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java index 10f3c05b..b55090f2 100644 --- a/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java +++ b/src/main/java/electrosphere/entity/state/inventory/InventoryUtils.java @@ -15,7 +15,11 @@ import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.InventoryMessage; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.server.player.Player; +import electrosphere.server.datacell.EntityDataCellMapper; +import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.datacell.utils.DataCellSearchUtils; +import electrosphere.server.datacell.utils.EntityLookupUtils; import electrosphere.util.Utilities; public class InventoryUtils { @@ -42,8 +46,17 @@ public class InventoryUtils { * @param target the entity to get inventory state from * @return The inventory state behavior tree or null */ - public static InventoryState getInventoryState(Entity target){ - return (InventoryState)target.getData(EntityDataStrings.INVENTORY_STATE); + public static InventoryState clientGetInventoryState(Entity target){ + return (InventoryState)target.getData(EntityDataStrings.CLIENT_INVENTORY_STATE); + } + + /** + * Gets the current inventory state + * @param target the entity to get inventory state from + * @return The inventory state behavior tree or null + */ + public static ServerInventoryState serverGetInventoryState(Entity target){ + return (ServerInventoryState)target.getData(EntityDataStrings.SERVER_INVENTORY_STATE); } /** @@ -51,8 +64,17 @@ public class InventoryUtils { * @param target The entity to attach inventory state to * @param state The inventory state to attach */ - public static void setInventoryState(Entity target, InventoryState state){ - target.putData(EntityDataStrings.INVENTORY_STATE, state); + public static void clientSetInventoryState(Entity target, InventoryState state){ + target.putData(EntityDataStrings.CLIENT_INVENTORY_STATE, state); + } + + /** + * Sets the current inventory state + * @param target The entity to attach inventory state to + * @param state The inventory state to attach + */ + public static void serverSetInventoryState(Entity target, ServerInventoryState state){ + target.putData(EntityDataStrings.SERVER_INVENTORY_STATE, state); } /** @@ -60,7 +82,7 @@ public class InventoryUtils { * @param creature The creature to store the item in * @param item The item to store */ - public static void attemptStoreItemTransform(Entity creature, Entity item){ + public static void serverAttemptStoreItemTransform(Entity creature, Entity item){ boolean creatureIsCreature = CreatureUtils.isCreature(creature); boolean itemIsItem = ItemUtils.isItem(item); boolean hasInventory = hasNaturalInventory(creature); @@ -73,17 +95,18 @@ public class InventoryUtils { UnrelationalInventoryState inventory = getNaturalInventory(creature); //destroy in-world entity and create in-inventory item //we're doing this so that we're not constantly sending networking messages for invisible entities attached to the player - Entity inventoryItem = ItemUtils.recreateContainerItem(item, creature); + Entity inventoryItem = ItemUtils.serverRecreateContainerItem(item, creature); //destroy the item that was left over - ItemUtils.destroyInWorldItem(item); + ItemUtils.serverDestroyInWorldItem(item); //store item in inventory inventory.addItem(inventoryItem); //set item containing parent ItemUtils.setContainingParent(inventoryItem, creature); //if we are the server, immediately send required packets if(Globals.RUN_SERVER){ - ServerDataCell dataCell = Globals.dataCellManager.getDataCellAtPoint(EntityUtils.getPosition(item)); - dataCell.removeEntity(item); + ServerDataCell dataCell = Globals.realmManager.getEntityRealm(item).getEntityDataCellMapper().getEntityDataCell(item); + // ServerDataCell dataCell = Globals.dataCellLocationResolver.getDataCellAtPoint(EntityUtils.getPosition(item),item); + dataCell.getScene().deregisterEntity(item); //broadcast destroy entity dataCell.broadcastNetworkMessage(EntityMessage.constructDestroyMessage(item.getId())); //tell controlling player that they have an item in their inventory @@ -106,11 +129,11 @@ public class InventoryUtils { public static void attemptStoreItem(Entity creature, Entity item){ if(Globals.RUN_SERVER){ //if we're the server, immediately attempt the transform - attemptStoreItemTransform(creature,item); + serverAttemptStoreItemTransform(creature,item); } else { //if we're the client, tell the server we want to try the transform NetworkMessage requestPickupMessage = InventoryMessage.constructaddItemToInventoryMessage( - Globals.entityManager.mapClientToServerId(item.getId()), + Globals.clientSceneWrapper.mapClientToServerId(item.getId()), ItemUtils.getType(item) ); Globals.clientConnection.queueOutgoingMessage(requestPickupMessage); @@ -118,12 +141,12 @@ public class InventoryUtils { } /** - * [CLIENT ONLY] Places an item of provided type in the parent container's natural inventory + * Places an item of provided type in the parent container's natural inventory * @param parentContainer The entity (typically a creature) which will receive the item in their natural inventory * @param type The type of item to place in the inventory * @return The in-inventory item entity */ - public static Entity constructInInventoryItem(Entity parentContainer, String type){ + public static Entity clientConstructInInventoryItem(Entity parentContainer, String type){ //sanity checks boolean creatureIsCreature = CreatureUtils.isCreature(parentContainer); boolean hasInventory = hasNaturalInventory(parentContainer); @@ -135,11 +158,11 @@ public class InventoryUtils { UnrelationalInventoryState inventory = getNaturalInventory(parentContainer); //create item //TODO: optimize by directly creating the container item instead of first spawning regular item - Entity spawnedItem = ItemUtils.spawnBasicItem(type); + Entity spawnedItem = ItemUtils.clientSpawnBasicItem(type); //convert to in-inventory - Entity inventoryItem = ItemUtils.recreateContainerItem(spawnedItem, parentContainer); + Entity inventoryItem = ItemUtils.clientRecreateContainerItem(spawnedItem, parentContainer); //destroy the item that was left over - ItemUtils.destroyInWorldItem(spawnedItem); + ItemUtils.clientDestroyInWorldItem(spawnedItem); //store item in inventory inventory.addItem(inventoryItem); //set item containing parent @@ -153,7 +176,7 @@ public class InventoryUtils { /** - * [SERVER ONLY] Attempts the transform to eject an item from an inventory, if this is the server it has added side effect of sending packets on success + * Attempts the transform to eject an item from an inventory, if this is the server it has added side effect of sending packets on success * @param creature The creature to eject the item from * @param item The item to eject */ @@ -184,13 +207,14 @@ public class InventoryUtils { if(realWorldItem != null){ //drop item EquipState equipState = EquipState.getEquipState(creature); - equipState.transformUnequipPoint(inventorySlot); + equipState.serverTransformUnequipPoint(inventorySlot); // equipState.serverAttemptUnequip(inventory.getItemSlot(item)); // //Tell clients to destroy the attached item Vector3d oldItemPos = EntityUtils.getPosition(realWorldItem); //get closest chunk - ServerDataCell dataCell = Globals.dataCellManager.getDataCellAtPoint(oldItemPos); + // ServerDataCell dataCell = Globals.dataCellLocationResolver.getDataCellAtPoint(oldItemPos,realWorldItem); + ServerDataCell dataCell = Globals.realmManager.getEntityRealm(realWorldItem).getEntityDataCellMapper().getEntityDataCell(realWorldItem); //broadcast destroy item NetworkMessage destroyMessage = InventoryMessage.constructserverCommandUnequipItemMessage(creature.getId(), inventorySlot); dataCell.broadcastNetworkMessage(destroyMessage); @@ -206,23 +230,17 @@ public class InventoryUtils { //tell the player they don't have the item anymore controllerPlayer.addMessage(InventoryMessage.constructremoveItemFromInventoryMessage(item.getId())); } - // - //compose item into in-world entity - Entity inWorldItem = ItemUtils.spawnBasicItem(ItemUtils.getType(item)); - //delete in container item - ItemUtils.destroyInInventoryItem(item); + //get parent realm + Realm realm = Globals.realmManager.getEntityRealm(creature); //find "in front of creature" Vector3d dropSpot = new Vector3d(EntityUtils.getPosition(creature)).add(CreatureUtils.getFacingVector(creature)); - //move in-world entity to in front of creature - EntityUtils.getPosition(inWorldItem).set(dropSpot); - //activate gravity - GravityUtils.attemptActivateGravity(inWorldItem); // - //add the item to closest data cell - //get closest chunk - ServerDataCell dataCell = Globals.dataCellManager.getDataCellAtPoint(dropSpot); - //add item - Globals.dataCellManager.initializeServerSideEntity(inWorldItem, dataCell); + //compose item into in-world entity + Entity inWorldItem = ItemUtils.serverSpawnBasicItem(realm,dropSpot,ItemUtils.getType(item)); + //delete in container item + ItemUtils.destroyInInventoryItem(item); + //activate gravity + GravityUtils.serverAttemptActivateGravity(inWorldItem); } } @@ -233,7 +251,7 @@ public class InventoryUtils { serverAttemptEjectItemTransform(creature,item); } else { //if we're the client, tell the server we want to try the transform - NetworkMessage requestPickupMessage = InventoryMessage.constructremoveItemFromInventoryMessage(Globals.entityManager.mapClientToServerId(item.getId())); + NetworkMessage requestPickupMessage = InventoryMessage.constructremoveItemFromInventoryMessage(Globals.clientSceneWrapper.mapClientToServerId(item.getId())); Globals.clientConnection.queueOutgoingMessage(requestPickupMessage); } } @@ -267,7 +285,7 @@ public class InventoryUtils { if(realWorldItem != null){ //drop item EquipState equipState = EquipState.getEquipState(creature); - equipState.transformUnequipPoint(inventory.getItemSlot(item)); + equipState.clientTransformUnequipPoint(inventory.getItemSlot(item)); } //remove item from inventory inventory.tryRemoveItem(item); diff --git a/src/main/java/electrosphere/entity/state/inventory/ServerInventoryState.java b/src/main/java/electrosphere/entity/state/inventory/ServerInventoryState.java new file mode 100644 index 00000000..eaa81d9d --- /dev/null +++ b/src/main/java/electrosphere/entity/state/inventory/ServerInventoryState.java @@ -0,0 +1,85 @@ +package electrosphere.entity.state.inventory; + +import java.util.concurrent.CopyOnWriteArrayList; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.equip.EquipState; +import electrosphere.entity.types.item.ItemUtils; +import electrosphere.game.data.creature.type.equip.EquipPoint; +import electrosphere.menu.WindowStrings; +import electrosphere.menu.WindowUtils; +import electrosphere.net.parser.net.message.InventoryMessage; +import electrosphere.net.server.protocol.InventoryProtocol; +import electrosphere.server.datacell.utils.EntityLookupUtils; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; + +/** + * Principally used to handle network messages related to inventory and thread synchronization + */ +public class ServerInventoryState implements BehaviorTree { + + CopyOnWriteArrayList networkMessageQueue = new CopyOnWriteArrayList(); + + Entity parent; + + ServerInventoryState() { + + } + + public static ServerInventoryState serverCreateInventoryState(Entity parent){ + ServerInventoryState rVal = new ServerInventoryState(); + rVal.parent = parent; + ServerBehaviorTreeUtils.attachBTreeToEntity(parent, rVal); + return rVal; + } + + @Override + public void simulate(float deltaTime) { + for(InventoryMessage message : networkMessageQueue){ + networkMessageQueue.remove(message); + switch(message.getMessageSubtype()){ + case ADDITEMTOINVENTORY: + InventoryUtils.attemptStoreItem(parent, EntityLookupUtils.getEntityById(message.getentityId())); + break; + case REMOVEITEMFROMINVENTORY: + InventoryUtils.attemptEjectItem(parent, EntityLookupUtils.getEntityById(message.getentityId())); + break; + case CLIENTREQUESTEQUIPITEM:{ + //item to equip + Entity target = EntityLookupUtils.getEntityById(message.getentityId()); + //perform transform if it makes sense + if(InventoryUtils.hasEquipInventory(parent) && InventoryUtils.hasNaturalInventory(parent) && EquipState.hasEquipState(parent)){ + EquipState equipState = EquipState.getEquipState(parent); + EquipPoint point = equipState.getEquipPoint(message.getequipPointId()); + equipState.commandAttemptEquip(target, point); + } + } + break; + case CLIENTREQUESTUNEQUIPITEM:{ + //make sure can unequip + if(InventoryUtils.hasEquipInventory(parent) && InventoryUtils.hasNaturalInventory(parent) && EquipState.hasEquipState(parent)){ + EquipState equipState = EquipState.getEquipState(parent); + EquipPoint point = equipState.getEquipPoint(message.getequipPointId()); + if(equipState.hasEquippedAtPoint(message.getequipPointId())){ + equipState.commandAttemptUnequip(message.getequipPointId()); + //tell player + } + } + } + break; + case SERVERCOMMANDUNEQUIPITEM: + case SERVERCOMMANDEQUIPITEM: + case SERVERCOMMANDMOVEITEMCONTAINER: + break; + } + } + } + + public void addNetworkMessage(InventoryMessage networkMessage) { + networkMessageQueue.add(networkMessage); + } + +} diff --git a/src/main/java/electrosphere/entity/state/ironsight/IronSightTree.java b/src/main/java/electrosphere/entity/state/ironsight/IronSightTree.java index 25885729..af110909 100644 --- a/src/main/java/electrosphere/entity/state/ironsight/IronSightTree.java +++ b/src/main/java/electrosphere/entity/state/ironsight/IronSightTree.java @@ -64,7 +64,7 @@ public class IronSightTree implements BehaviorTree { public static void attachIronSightTree(Entity player){ IronSightTree ironSightTree = new IronSightTree(); player.putData(EntityDataStrings.IRON_SIGHT_TREE, ironSightTree); - Globals.entityManager.registerBehaviorTree(ironSightTree); + Globals.clientSceneWrapper.getScene().registerBehaviorTree(ironSightTree); } } diff --git a/src/main/java/electrosphere/entity/state/life/LifeState.java b/src/main/java/electrosphere/entity/state/life/LifeState.java index 88626d39..160c47b4 100644 --- a/src/main/java/electrosphere/entity/state/life/LifeState.java +++ b/src/main/java/electrosphere/entity/state/life/LifeState.java @@ -15,6 +15,7 @@ import electrosphere.game.data.creature.type.HealthSystem; import electrosphere.net.parser.net.message.CharacterMessage; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.renderer.actor.Actor; +import electrosphere.server.datacell.utils.DataCellSearchUtils; public class LifeState implements BehaviorTree { @@ -114,13 +115,11 @@ public class LifeState implements BehaviorTree { if(Globals.RUN_SERVER){ state = LifeStateEnum.DYING; Vector3d position = EntityUtils.getPosition(parent); - Globals.dataCellManager.sendNetworkMessageToChunk( + DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( EntityMessage.constructKillMessage( Main.getCurrentFrame(), parent.getId() - ), - Globals.serverWorldData.convertRealToChunkSpace(position.x), - Globals.serverWorldData.convertRealToChunkSpace(position.z) + ) ); } } else { diff --git a/src/main/java/electrosphere/entity/state/movement/AirplaneMovementTree.java b/src/main/java/electrosphere/entity/state/movement/AirplaneMovementTree.java index 9181d664..c0dd9520 100644 --- a/src/main/java/electrosphere/entity/state/movement/AirplaneMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/AirplaneMovementTree.java @@ -18,6 +18,7 @@ import electrosphere.game.collision.collidable.Collidable; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.anim.Animation; +import electrosphere.server.datacell.utils.DataCellSearchUtils; public class AirplaneMovementTree implements BehaviorTree { @@ -243,7 +244,7 @@ public class AirplaneMovementTree implements BehaviorTree { stateNumber = 1; break; } - Globals.dataCellManager.sendNetworkMessageToChunk( + DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( EntityMessage.constructmoveUpdateMessage( parent.getId(), Main.getCurrentFrame(), @@ -256,9 +257,7 @@ public class AirplaneMovementTree implements BehaviorTree { rotation.w, velocity, stateNumber - ), - Globals.serverWorldData.convertRealToChunkSpace(position.x), - Globals.serverWorldData.convertRealToChunkSpace(position.z) + ) ); } } diff --git a/src/main/java/electrosphere/entity/state/movement/GroundMovementTree.java b/src/main/java/electrosphere/entity/state/movement/GroundMovementTree.java index 3c4a3874..44a281ae 100644 --- a/src/main/java/electrosphere/entity/state/movement/GroundMovementTree.java +++ b/src/main/java/electrosphere/entity/state/movement/GroundMovementTree.java @@ -22,6 +22,7 @@ import electrosphere.game.collision.collidable.Collidable; import electrosphere.net.NetUtils; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.renderer.anim.Animation; +import electrosphere.server.datacell.utils.DataCellSearchUtils; import electrosphere.renderer.Model; import electrosphere.renderer.actor.Actor; @@ -201,9 +202,7 @@ public class GroundMovementTree implements BehaviorTree { // System.out.println("MOVE to " + message.getX() + " " + message.getY() + " " + message.getZ()); switch(message.getMessageSubtype()){ case MOVE: - if(Globals.RUN_CLIENT){ - position.set(message.getpositionX(), message.getpositionY(), message.getpositionZ()); - } + position.set(message.getpositionX(), message.getpositionY(), message.getpositionZ()); break; case SETFACING: break; @@ -214,17 +213,17 @@ public class GroundMovementTree implements BehaviorTree { case 0: state = MovementTreeState.STARTUP; // System.out.println("Set state STARTUP"); - GravityUtils.attemptActivateGravity(parent); + GravityUtils.clientAttemptActivateGravity(parent); break; case 1: state = MovementTreeState.MOVE; // System.out.println("Set state MOVE"); - GravityUtils.attemptActivateGravity(parent); + GravityUtils.clientAttemptActivateGravity(parent); break; case 2: state = MovementTreeState.SLOWDOWN; // System.out.println("Set state SLOWDOWN"); - GravityUtils.attemptActivateGravity(parent); + GravityUtils.clientAttemptActivateGravity(parent); break; case 3: state = MovementTreeState.IDLE; @@ -288,27 +287,8 @@ public class GroundMovementTree implements BehaviorTree { // position.set(newPosition); rotation.set(movementQuaternion); - GravityUtils.attemptActivateGravity(parent); + GravityUtils.clientAttemptActivateGravity(parent); - if(Globals.RUN_SERVER){ - Globals.dataCellManager.sendNetworkMessageToChunk( - EntityMessage.constructmoveUpdateMessage( - parent.getId(), - Main.getCurrentFrame(), - position.x, - position.y, - position.z, - rotation.x, - rotation.y, - rotation.z, - rotation.w, - velocity, - 0 - ), - Globals.serverWorldData.convertRealToChunkSpace(position.x), - Globals.serverWorldData.convertRealToChunkSpace(position.z) - ); - } break; case MOVE: //check if can restart animation @@ -340,27 +320,8 @@ public class GroundMovementTree implements BehaviorTree { // position.set(newPosition); rotation.set(movementQuaternion); - GravityUtils.attemptActivateGravity(parent); + GravityUtils.clientAttemptActivateGravity(parent); - if(Globals.RUN_SERVER){ - Globals.dataCellManager.sendNetworkMessageToChunk( - EntityMessage.constructmoveUpdateMessage( - parent.getId(), - Main.getCurrentFrame(), - position.x, - position.y, - position.z, - rotation.x, - rotation.y, - rotation.z, - rotation.w, - velocity, - 1 - ), - Globals.serverWorldData.convertRealToChunkSpace(position.x), - Globals.serverWorldData.convertRealToChunkSpace(position.z) - ); - } break; case SLOWDOWN: //run slowdown code @@ -400,27 +361,8 @@ public class GroundMovementTree implements BehaviorTree { // position.set(newPosition); rotation.set(movementQuaternion); - GravityUtils.attemptActivateGravity(parent); + GravityUtils.clientAttemptActivateGravity(parent); - if(Globals.RUN_SERVER){ - Globals.dataCellManager.sendNetworkMessageToChunk( - EntityMessage.constructmoveUpdateMessage( - parent.getId(), - Main.getCurrentFrame(), - position.x, - position.y, - position.z, - rotation.x, - rotation.y, - rotation.z, - rotation.w, - velocity, - 2 - ), - Globals.serverWorldData.convertRealToChunkSpace(position.x), - Globals.serverWorldData.convertRealToChunkSpace(position.z) - ); - } break; case IDLE: // body.clearForces(); @@ -441,7 +383,7 @@ public class GroundMovementTree implements BehaviorTree { public boolean canStartMoving(){ boolean rVal = true; - if(parent.containsKey(EntityDataStrings.ATTACK_TREE) && ((AttackTree)parent.getData(EntityDataStrings.ATTACK_TREE)).getState() != AttackTreeState.IDLE){ + if(parent.containsKey(EntityDataStrings.CLIENT_ATTACK_TREE) && ((AttackTree)parent.getData(EntityDataStrings.CLIENT_ATTACK_TREE)).getState() != AttackTreeState.IDLE){ rVal = false; } return rVal; @@ -475,11 +417,11 @@ public class GroundMovementTree implements BehaviorTree { this.sprintTree = sprintTree; } - public void setJumpTree(JumpTree jumpTree){ + public void setClientJumpTree(JumpTree jumpTree){ this.jumpTree = jumpTree; } - public void setFallTree(FallTree fallTree){ + public void setClientFallTree(FallTree fallTree){ this.fallTree = fallTree; } diff --git a/src/main/java/electrosphere/entity/state/movement/JumpTree.java b/src/main/java/electrosphere/entity/state/movement/JumpTree.java index ec5b7541..f0143d14 100644 --- a/src/main/java/electrosphere/entity/state/movement/JumpTree.java +++ b/src/main/java/electrosphere/entity/state/movement/JumpTree.java @@ -44,7 +44,7 @@ public class JumpTree implements BehaviorTree { state = JumpState.ACTIVE; currentFrame = 0; currentJumpForce = jumpForce; - GravityUtils.attemptActivateGravity(parent); + GravityUtils.clientAttemptActivateGravity(parent); } } @@ -67,7 +67,7 @@ public class JumpTree implements BehaviorTree { //potentially disable if(currentFrame >= jumpFrames){ state = JumpState.AWAITING_LAND; - GravityUtils.attemptActivateGravity(parent); + GravityUtils.clientAttemptActivateGravity(parent); } break; case INACTIVE: @@ -77,8 +77,8 @@ public class JumpTree implements BehaviorTree { } } - public static JumpTree getJumpTree(Entity parent){ - return (JumpTree)parent.getData(EntityDataStrings.JUMP_TREE); + public static JumpTree getClientJumpTree(Entity parent){ + return (JumpTree)parent.getData(EntityDataStrings.CLIENT_JUMP_TREE); } public void land(){ diff --git a/src/main/java/electrosphere/entity/state/movement/ProjectileTree.java b/src/main/java/electrosphere/entity/state/movement/ProjectileTree.java index fdc48a12..341d68bd 100644 --- a/src/main/java/electrosphere/entity/state/movement/ProjectileTree.java +++ b/src/main/java/electrosphere/entity/state/movement/ProjectileTree.java @@ -8,6 +8,7 @@ import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.BehaviorTree; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; public class ProjectileTree implements BehaviorTree { @@ -44,8 +45,8 @@ public class ProjectileTree implements BehaviorTree { lifeCurrent++; if(lifeCurrent >= maxLife){ - Globals.entityManager.deregisterEntity(parent); - Globals.entityManager.deregisterBehaviorTree(this); + EntityUtils.cleanUpEntity(parent); + ServerBehaviorTreeUtils.detatchBTreeFromEntity(parent,this); } Vector3d positionCurrent = EntityUtils.getPosition(parent); diff --git a/src/main/java/electrosphere/entity/state/movement/ServerFallTree.java b/src/main/java/electrosphere/entity/state/movement/ServerFallTree.java new file mode 100644 index 00000000..ba589cc8 --- /dev/null +++ b/src/main/java/electrosphere/entity/state/movement/ServerFallTree.java @@ -0,0 +1,101 @@ +package electrosphere.entity.state.movement; + +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.renderer.actor.Actor; + +public class ServerFallTree implements BehaviorTree { + + static enum FallState { + ACTIVE, + INACTIVE, + } + + FallState state = FallState.INACTIVE; + + String animationFall = "Armature|Fall"; + String animationLand = "Armature|Land"; + + Entity parent; + + ServerJumpTree jumpTree; + + public ServerFallTree(Entity parent){ + this.parent = parent; + } + + @Override + public void simulate(float deltaTime) { + Actor entityActor = EntityUtils.getActor(parent); + switch(state){ + case ACTIVE: + if(entityActor != null){ + String animationToPlay = determineCorrectAnimation(); + if( + !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) && + (jumpTree == null || !jumpTree.isJumping()) + ){ + entityActor.playAnimation(animationToPlay,1); + entityActor.incrementAnimationTime(0.0001); + } + } + break; + case INACTIVE: + break; + } + } + + public void start(){ + state = FallState.ACTIVE; + } + + public boolean isFalling(){ + return state == FallState.ACTIVE; + } + + public void land(){ + if(state != FallState.INACTIVE){ + state = FallState.INACTIVE; + Actor entityActor = EntityUtils.getActor(parent); + if(entityActor != null){ + String animationToPlay = determineCorrectAnimation(); + if( + !entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay) + ){ + entityActor.playAnimation(animationToPlay,1); + entityActor.incrementAnimationTime(0.0001); + } + } + } + } + + public static ServerFallTree getFallTree(Entity parent){ + return (ServerFallTree)parent.getData(EntityDataStrings.FALL_TREE); + } + + String determineCorrectAnimation(){ + switch(state){ + case ACTIVE: + return animationFall; + case INACTIVE: + return animationLand; + default: + return animationLand; + } + } + + public void setServerJumpTree(ServerJumpTree jumpTree){ + this.jumpTree = jumpTree; + } + + public void setAnimationFall(String animationName){ + animationFall = animationName; + } + + public void setAnimationLand(String animationName){ + animationLand = animationName; + } + +} diff --git a/src/main/java/electrosphere/entity/state/movement/ServerGroundMovementTree.java b/src/main/java/electrosphere/entity/state/movement/ServerGroundMovementTree.java new file mode 100644 index 00000000..5e15c2ec --- /dev/null +++ b/src/main/java/electrosphere/entity/state/movement/ServerGroundMovementTree.java @@ -0,0 +1,672 @@ +package electrosphere.entity.state.movement; + +import electrosphere.entity.state.collidable.Impulse; +import electrosphere.entity.state.gravity.GravityTree; +import electrosphere.entity.state.gravity.GravityUtils; +import electrosphere.collision.dispatch.CollisionObject; +import electrosphere.dynamics.RigidBody; +import electrosphere.engine.Globals; +import electrosphere.engine.Main; +import electrosphere.entity.types.camera.CameraEntityUtils; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.attack.ServerAttackTree; +import electrosphere.entity.state.attack.ServerAttackTree.AttackTreeState; +import electrosphere.entity.state.movement.ServerSprintTree.SprintTreeState; +import electrosphere.game.collision.CollisionEngine; +import electrosphere.game.collision.PhysicsUtils; +import electrosphere.game.collision.collidable.Collidable; +import electrosphere.net.NetUtils; +import electrosphere.net.parser.net.message.EntityMessage; +import electrosphere.renderer.anim.Animation; +import electrosphere.server.datacell.utils.DataCellSearchUtils; +import electrosphere.server.poseactor.PoseActor; +import electrosphere.renderer.Model; +import electrosphere.renderer.actor.Actor; + +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import org.joml.Quaternionf; +import org.joml.Vector3d; +import org.joml.Vector3f; + +/* +Behavior tree for movement in an entity +*/ +public class ServerGroundMovementTree implements BehaviorTree { + + public static enum MovementTreeState { + STARTUP, + MOVE, + SLOWDOWN, + IDLE, + } + + public static enum MovementRelativeFacing { + FORWARD, + LEFT, + RIGHT, + BACKWARD, + FORWARD_LEFT, + FORWARD_RIGHT, + BACKWARD_LEFT, + BACKWARD_RIGHT, + } + + static final double STATE_DIFFERENCE_HARD_UPDATE_THRESHOLD = 1.0; + static final double STATE_DIFFERENCE_SOFT_UPDATE_THRESHOLD = 0.2; + static final double SOFT_UPDATE_MULTIPLIER = 0.1; + + String animationStartUp = Animation.ANIMATION_MOVEMENT_STARTUP; + String animationMain = Animation.ANIMATION_MOVEMENT_MOVE; + String animationSlowDown = Animation.ANIMATION_MOVEMENT_MOVE; + String animationSprintStart = Animation.ANIMATION_SPRINT_STARTUP; + String animationSprint = Animation.ANIMATION_SPRINT; + String animationSprintWindDown = Animation.ANIMATION_SPRINT_WINDDOWN; + + MovementTreeState state; + MovementRelativeFacing facing; + + ServerSprintTree sprintTree; + ServerJumpTree jumpTree; + ServerFallTree fallTree; + + Entity parent; + + Collidable collidable; + + CopyOnWriteArrayList networkMessageQueue = new CopyOnWriteArrayList(); + + long lastUpdateTime = 0; + + + public ServerGroundMovementTree(Entity e, Collidable collidable){ + state = MovementTreeState.IDLE; + facing = MovementRelativeFacing.FORWARD; + parent = e; + this.collidable = collidable; + } + + public MovementTreeState getState(){ + return state; + } + + public void start(MovementRelativeFacing facing){ + if(canStartMoving()){ + this.facing = facing; + state = MovementTreeState.STARTUP; + //if we aren't the server, alert the server we intend to walk forward + if(!Globals.RUN_SERVER){ + Vector3d position = EntityUtils.getPosition(parent); + Quaternionf rotation = EntityUtils.getRotation(parent); + Vector3d facingVector = CreatureUtils.getFacingVector(parent); + float velocity = CreatureUtils.getVelocity(parent); + Globals.clientConnection.queueOutgoingMessage( + EntityMessage.constructmoveUpdateMessage( + parent.getId(), + Main.getCurrentFrame(), + position.x, + position.y, + position.z, + rotation.x, + rotation.y, + rotation.z, + rotation.w, + velocity, + 0 //magic number corresponding to state startup + ) + ); + } + } + } + + public void interrupt(){ + state = MovementTreeState.IDLE; + CreatureUtils.setVelocity(parent, 0); + } + + public void slowdown(){ + state = MovementTreeState.SLOWDOWN; + //if we aren't the server, alert the server we intend to slow down + if(!Globals.RUN_SERVER){ + Vector3d position = EntityUtils.getPosition(parent); + Quaternionf rotation = EntityUtils.getRotation(parent); + Vector3d facingVector = CreatureUtils.getFacingVector(parent); + float velocity = CreatureUtils.getVelocity(parent); + Globals.clientConnection.queueOutgoingMessage( + EntityMessage.constructmoveUpdateMessage( + parent.getId(), + Main.getCurrentFrame(), + position.x, + position.y, + position.z, + rotation.x, + rotation.y, + rotation.z, + rotation.w, + velocity, + 2 //magic number corresponding to state slowdown + ) + ); + } + } + + public void simulate(float deltaTime){ + float velocity = CreatureUtils.getVelocity(parent); + float acceleration = CreatureUtils.getAcceleration(parent); + float maxNaturalVelocity = sprintTree != null && sprintTree.state == SprintTreeState.SPRINTING ? sprintTree.maxVelocity : CreatureUtils.getMaxNaturalVelocity(parent); + PoseActor entityPoseActor = EntityUtils.getPoseActor(parent); +// Model entityModel = Globals.assetManager.fetchModel(EntityUtils.getEntityModelPath(parent)); + Vector3d position = EntityUtils.getPosition(parent); + Vector3d facingVector = CreatureUtils.getFacingVector(parent); + Vector3d movementVector = new Vector3d(facingVector); + switch(facing){ + case FORWARD: + movementVector.normalize(); + break; + case LEFT: + movementVector.rotateY((float)(90 * Math.PI / 180)).normalize(); + break; + case RIGHT: + movementVector.rotateY((float)(-90 * Math.PI / 180)).normalize(); + break; + case BACKWARD: + movementVector.x = -movementVector.x; + movementVector.z = -movementVector.z; + movementVector.normalize(); + break; + case FORWARD_LEFT: + movementVector.rotateY((float)(45 * Math.PI / 180)).normalize(); + break; + case FORWARD_RIGHT: + movementVector.rotateY((float)(-45 * Math.PI / 180)).normalize(); + break; + case BACKWARD_LEFT: + movementVector.rotateY((float)(135 * Math.PI / 180)).normalize(); + break; + case BACKWARD_RIGHT: + movementVector.rotateY((float)(-135 * Math.PI / 180)).normalize(); + break; + } +// float movementYaw = CameraEntityUtils.getCameraYaw(Globals.playerCamera); + Quaternionf movementQuaternion = new Quaternionf().rotationTo(new Vector3f(0,0,1), new Vector3f((float)facingVector.x,0,(float)facingVector.z)).normalize(); + Quaternionf 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 MOVE: + break; + case SETFACING: + break; + case MOVEUPDATE: + if(updateTime > lastUpdateTime){ + lastUpdateTime = updateTime; + switch(message.gettreeState()){ + case 0: + state = MovementTreeState.STARTUP; + // System.out.println("Set state STARTUP"); + GravityUtils.serverAttemptActivateGravity(parent); + break; + case 1: + state = MovementTreeState.MOVE; +// System.out.println("Set state MOVE"); + GravityUtils.serverAttemptActivateGravity(parent); + break; + case 2: + state = MovementTreeState.SLOWDOWN; + // System.out.println("Set state SLOWDOWN"); + GravityUtils.serverAttemptActivateGravity(parent); + break; + case 3: + state = MovementTreeState.IDLE; + // System.out.println("Set state IDLE"); + break; + } + //we want to always update the server facing vector with where the client says they're facing + 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){ + case STARTUP: + if(entityPoseActor != null){ + String animationToPlay = determineCorrectAnimation(); + if( + !entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationToPlay) && + (jumpTree == null || !jumpTree.isJumping()) && + (fallTree == null || !fallTree.isFalling()) + ){ + entityPoseActor.playAnimation(animationToPlay,1); + entityPoseActor.incrementAnimationTime(0.0001); + } + } + //run startup code + velocity = velocity + acceleration * Main.deltaFrames; + //check if can transition state + if(velocity >= maxNaturalVelocity){ + velocity = maxNaturalVelocity; + state = MovementTreeState.MOVE; + } + CreatureUtils.setVelocity(parent, velocity); +// body.applyCentralForce(PhysicsUtils.jomlToVecmathVector3f(new Vector3f(movementVector.x,0,movementVector.z).normalize().mul(velocity))); + // EntityUtils.getRotation(parent).set(movementQuaternion); +// //move the entity +// newPosition = new Vector3d(position).add(new Vector3d(movementVector).mul(velocity).mul(Main.deltaTime)); +// //check/update if collision +// if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){ +// newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition); +// } +// //actually update + collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement")); +// position.set(newPosition); + rotation.set(movementQuaternion); + + GravityUtils.serverAttemptActivateGravity(parent); + + DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( + EntityMessage.constructmoveUpdateMessage( + parent.getId(), + Main.getCurrentFrame(), + position.x, + position.y, + position.z, + rotation.x, + rotation.y, + rotation.z, + rotation.w, + velocity, + 0 + ) + ); + break; + case MOVE: + //check if can restart animation + //if yes, restart animation + if(entityPoseActor != null){ + String animationToPlay = determineCorrectAnimation(); + if( + !entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationToPlay) && + (jumpTree == null || !jumpTree.isJumping()) && + (fallTree == null || !fallTree.isFalling()) + ){ + entityPoseActor.playAnimation(animationToPlay,1); + entityPoseActor.incrementAnimationTime(0.0001); + } + } + if(velocity != maxNaturalVelocity){ + velocity = maxNaturalVelocity; + CreatureUtils.setVelocity(parent, velocity); + } +// body.applyCentralForce(PhysicsUtils.jomlToVecmathVector3f(force)); + // EntityUtils.getRotation(parent).set(movementQuaternion); + //check if can move forward (collision engine) + //if can, move forward by entity movement stats +// newPosition = new Vector3d(position).add(new Vector3d(movementVector).mul(velocity).mul(Main.deltaTime)); +// if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){ +// newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition); +// } + collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement")); +// position.set(newPosition); + rotation.set(movementQuaternion); + + GravityUtils.serverAttemptActivateGravity(parent); + + DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( + EntityMessage.constructmoveUpdateMessage( + parent.getId(), + Main.getCurrentFrame(), + position.x, + position.y, + position.z, + rotation.x, + rotation.y, + rotation.z, + rotation.w, + velocity, + 1 + ) + ); + break; + case SLOWDOWN: + //run slowdown code + if(entityPoseActor != null){ + String animationToPlay = determineCorrectAnimation(); + if( + !entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationToPlay) && + (jumpTree == null || !jumpTree.isJumping()) && + (fallTree == null || !fallTree.isFalling()) + ){ + entityPoseActor.playAnimation(animationToPlay,1); + entityPoseActor.incrementAnimationTime(0.0001); + } + } + //velocity stuff + velocity = velocity - acceleration * Main.deltaFrames; + //check if can transition state + if(velocity <= 0){ + velocity = 0; + state = MovementTreeState.IDLE; + if(entityPoseActor != null){ + String animationToPlay = determineCorrectAnimation(); + if(entityPoseActor.isPlayingAnimation() && entityPoseActor.isPlayingAnimation(animationToPlay)){ + entityPoseActor.stopAnimation(animationToPlay); + } + } + } + CreatureUtils.setVelocity(parent, velocity); +// body.applyCentralForce(PhysicsUtils.jomlToVecmathVector3f(new Vector3f(movementVector).mul(-1.0f).normalize().mul(velocity))); + // EntityUtils.getRotation(parent).rotationTo(new Vector3f(0,0,1), new Vector3f((float)movementVector.x,(float)movementVector.y,(float)movementVector.z)); + //move the entity +// newPosition = new Vector3d(position).add(new Vector3d(movementVector).mul(velocity).mul(Main.deltaTime)); +// if(!Globals.collisionEngine.checkCanOccupyPosition(Globals.commonWorldData, parent, newPosition)){ +// newPosition = Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData, parent, newPosition); +// } + collidable.addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), velocity * Main.deltaFrames, "movement")); +// position.set(newPosition); + rotation.set(movementQuaternion); + + GravityUtils.serverAttemptActivateGravity(parent); + + DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage( + EntityMessage.constructmoveUpdateMessage( + parent.getId(), + Main.getCurrentFrame(), + position.x, + position.y, + position.z, + rotation.x, + rotation.y, + rotation.z, + rotation.w, + velocity, + 2 + ) + ); + break; + case IDLE: +// body.clearForces(); + +// if(Globals.collisionEngine.gravityCheck(Globals.commonWorldData, parent)){ +// position.set(Globals.collisionEngine.suggestMovementPosition(Globals.commonWorldData,parent,new Vector3f(position.x,position.y - 9.8f,position.z))); +// } +// position.set(new Vector3f(position.x,position.y - 0.08f,position.z)); +// bodyTransformMatrix = new javax.vecmath.Matrix4f(PhysicsUtils.jomlToVecmathQuaternionf(rotation),PhysicsUtils.jomlToVecmathVector3f(position),1.0f); +// body.setWorldTransform(new com.bulletphysics.linearmath.Transform(bodyTransformMatrix)); + break; + } + } + + public void addNetworkMessage(EntityMessage networkMessage) { + networkMessageQueue.add(networkMessage); + } + + public boolean canStartMoving(){ + boolean rVal = true; + if(parent.containsKey(EntityDataStrings.SERVER_ATTACK_TREE) && ((ServerAttackTree)parent.getData(EntityDataStrings.SERVER_ATTACK_TREE)).getState() != AttackTreeState.IDLE){ + rVal = false; + } + return rVal; + } + + public void setAnimationStartUp(String animationStartUp) { + this.animationStartUp = animationStartUp; + } + + public void setAnimationMain(String animationMain) { + this.animationMain = animationMain; + } + + public void setAnimationSlowDown(String animationSlowDown) { + this.animationSlowDown = animationSlowDown; + } + + public void setAnimationSprintStartUp(String animationSprintStartUp){ + this.animationSprintStart = animationSprintStartUp; + } + + public void setAnimationSprint(String animationSprint){ + this.animationSprint = animationSprint; + } + + public void setAnimationSprintWindDown(String animationSprintWindDown){ + this.animationSprintWindDown = animationSprintWindDown; + } + + public void setServerSprintTree(ServerSprintTree sprintTree){ + this.sprintTree = sprintTree; + } + + public void setServerJumpTree(ServerJumpTree jumpTree){ + this.jumpTree = jumpTree; + } + + public void setServerFallTree(ServerFallTree fallTree){ + this.fallTree = fallTree; + } + + public MovementRelativeFacing getFacing(){ + return facing; + } + + public String determineCorrectAnimation(){ + String rVal = ""; + if(sprintTree != null){ + switch(sprintTree.state){ + case SPRINTING: + switch(state){ + case IDLE: + break; + case STARTUP: + rVal = animationSprintStart; + break; + case MOVE: + rVal = animationSprint; + break; + case SLOWDOWN: + rVal = animationSprintWindDown; + break; + } + break; + case NOT_SPRINTING: + switch(state){ + case IDLE: + break; + case STARTUP: + switch(facing){ + case FORWARD: + rVal = animationStartUp; + break; + case BACKWARD: + rVal = animationStartUp; + break; + case LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case FORWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case FORWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case BACKWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case BACKWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + } + break; + case MOVE: + switch(facing){ + case FORWARD: + rVal = animationMain; + break; + case BACKWARD: + rVal = animationMain; + break; + case LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case FORWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case FORWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case BACKWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case BACKWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + } + break; + case SLOWDOWN: + switch(facing){ + case FORWARD: + rVal = animationSlowDown; + break; + case BACKWARD: + rVal = animationSlowDown; + break; + case LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case FORWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case FORWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case BACKWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case BACKWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + } + break; + } + break; + } + } else { + switch(state){ + case IDLE: + break; + case STARTUP: + switch(facing){ + case FORWARD: + rVal = animationStartUp; + break; + case BACKWARD: + rVal = animationStartUp; + break; + case LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case FORWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case FORWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case BACKWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case BACKWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + } + break; + case MOVE: + switch(facing){ + case FORWARD: + rVal = animationMain; + break; + case BACKWARD: + rVal = animationMain; + break; + case LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case FORWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case FORWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case BACKWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case BACKWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + } + break; + case SLOWDOWN: + switch(facing){ + case FORWARD: + rVal = animationSlowDown; + break; + case BACKWARD: + rVal = animationSlowDown; + break; + case LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case FORWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case FORWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + case BACKWARD_LEFT: + rVal = Animation.ANIMATION_WALK_LEFT; + break; + case BACKWARD_RIGHT: + rVal = Animation.ANIMATION_WALK_RIGHT; + break; + } + break; + } + } + + + return rVal; + } + +} diff --git a/src/main/java/electrosphere/entity/state/movement/ServerJumpTree.java b/src/main/java/electrosphere/entity/state/movement/ServerJumpTree.java new file mode 100644 index 00000000..e56b48f4 --- /dev/null +++ b/src/main/java/electrosphere/entity/state/movement/ServerJumpTree.java @@ -0,0 +1,102 @@ +package electrosphere.entity.state.movement; + +import org.joml.Vector3d; + +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.collidable.Impulse; +import electrosphere.entity.state.gravity.GravityUtils; +import electrosphere.entity.types.collision.CollisionObjUtils; +import electrosphere.game.collision.collidable.Collidable; +import electrosphere.renderer.actor.Actor; + +public class ServerJumpTree implements BehaviorTree { + + static enum JumpState { + INACTIVE, + ACTIVE, + AWAITING_LAND, + } + + JumpState state = JumpState.INACTIVE; + + String animationJump = "Armature|Jump"; + + Entity parent; + + int jumpFrames = 0; + int currentFrame = 0; + float jumpForce = 10.0f; + float currentJumpForce = jumpForce; + + static final float jumpFalloff = 0.99f; + + public ServerJumpTree(Entity parent, int jumpFrames, float jumpForce){ + this.parent = parent; + this.jumpFrames = jumpFrames; + this.jumpForce = jumpForce; + } + + public void start(){ + if(state == JumpState.INACTIVE){ + state = JumpState.ACTIVE; + currentFrame = 0; + currentJumpForce = jumpForce; + GravityUtils.serverAttemptActivateGravity(parent); + } + } + + @Override + public void simulate(float deltaTime) { + Actor entityActor = EntityUtils.getActor(parent); + switch(state){ + case ACTIVE: + if(entityActor != null){ + String animationToPlay = determineCorrectAnimation(); + if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationToPlay)){ + entityActor.playAnimation(animationToPlay,1); + entityActor.incrementAnimationTime(0.0001); + } + } + currentFrame++; + currentJumpForce = currentJumpForce * jumpFalloff; + //push parent up + CollisionObjUtils.getCollidable(parent).addImpulse(new Impulse(new Vector3d(0,1,0), new Vector3d(0,0,0), new Vector3d(EntityUtils.getPosition(parent)), currentJumpForce, Collidable.TYPE_FORCE)); + //potentially disable + if(currentFrame >= jumpFrames){ + state = JumpState.AWAITING_LAND; + GravityUtils.serverAttemptActivateGravity(parent); + } + break; + case INACTIVE: + break; + case AWAITING_LAND: + break; + } + } + + public static ServerJumpTree getServerJumpTree(Entity parent){ + return (ServerJumpTree)parent.getData(EntityDataStrings.SERVER_JUMP_TREE); + } + + public void land(){ + if(state != JumpState.INACTIVE && currentFrame > 2){ + state = JumpState.INACTIVE; + } + } + + public boolean isJumping(){ + return state == JumpState.ACTIVE; + } + + String determineCorrectAnimation(){ + return animationJump; + } + + public void setAnimationJump(String animationName){ + animationJump = animationName; + } + +} diff --git a/src/main/java/electrosphere/entity/state/movement/ServerSprintTree.java b/src/main/java/electrosphere/entity/state/movement/ServerSprintTree.java new file mode 100644 index 00000000..af952993 --- /dev/null +++ b/src/main/java/electrosphere/entity/state/movement/ServerSprintTree.java @@ -0,0 +1,76 @@ +package electrosphere.entity.state.movement; + +import electrosphere.engine.Main; +import electrosphere.entity.Entity; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.movement.ServerGroundMovementTree.MovementTreeState; + +/** + * + * @author amaterasu + */ +public class ServerSprintTree implements BehaviorTree { + + public static enum SprintTreeState { + SPRINTING, + NOT_SPRINTING, + } + + SprintTreeState state; + + ServerGroundMovementTree groundMovementTree; + + Entity parent; + + int staminaCurrent = 0; + int staminaMax = 1; + + float maxVelocity; + + public ServerSprintTree(Entity e, float maxVelocity, int staminaMax){ + state = SprintTreeState.NOT_SPRINTING; + parent = e; + this.maxVelocity = maxVelocity; + this.staminaMax = staminaMax; + } + + public SprintTreeState getState(){ + return state; + } + + public void start(){ + if(staminaCurrent > 0){ + // System.out.println("Starting sprinting"); + state = SprintTreeState.SPRINTING; + } + } + + public void stop(){ + state = SprintTreeState.NOT_SPRINTING; + } + + @Override + public void simulate(float deltaTime){ + switch(state){ + case SPRINTING: + if(groundMovementTree != null && groundMovementTree.getState() != MovementTreeState.IDLE){ + staminaCurrent--; + if(staminaCurrent < 1){ + state = SprintTreeState.NOT_SPRINTING; + } + } + break; + case NOT_SPRINTING: + staminaCurrent++; + if(staminaCurrent > staminaMax){ + staminaCurrent = staminaMax; + } + break; + } + } + + public void setServerGroundMovementTree(ServerGroundMovementTree groundMovementTree){ + this.groundMovementTree = groundMovementTree; + } + +} diff --git a/src/main/java/electrosphere/entity/state/rotator/RotatorTree.java b/src/main/java/electrosphere/entity/state/rotator/RotatorTree.java index 8a2eaf93..7f1e59f8 100644 --- a/src/main/java/electrosphere/entity/state/rotator/RotatorTree.java +++ b/src/main/java/electrosphere/entity/state/rotator/RotatorTree.java @@ -109,8 +109,8 @@ public class RotatorTree implements BehaviorTree{ return (float)Math.asin(-2.0*(quat.x*quat.z - quat.w*quat.y)); } - public static RotatorTree getRotatorTree(Entity parent){ - return (RotatorTree)parent.getData(EntityDataStrings.ROTATOR_TREE); + public static RotatorTree getClientRotatorTree(Entity parent){ + return (RotatorTree)parent.getData(EntityDataStrings.CLIENT_ROTATOR_TREE); } } diff --git a/src/main/java/electrosphere/entity/state/rotator/ServerRotatorTree.java b/src/main/java/electrosphere/entity/state/rotator/ServerRotatorTree.java new file mode 100644 index 00000000..b1062728 --- /dev/null +++ b/src/main/java/electrosphere/entity/state/rotator/ServerRotatorTree.java @@ -0,0 +1,117 @@ +package electrosphere.entity.state.rotator; + +import java.util.LinkedList; +import java.util.List; + +import org.joml.Quaternionf; +import org.joml.Vector3d; +import org.joml.Vector3f; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.entity.state.view.ViewUtils; +import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.renderer.actor.Actor; +import electrosphere.renderer.actor.ActorBoneRotator; +import electrosphere.server.poseactor.PoseActor; + +public class ServerRotatorTree implements BehaviorTree{ + + public static enum RotatorTreeState { + ACTIVE, + INACTIVE, + } + + RotatorTreeState state; + + Entity parent; + PoseActor entityPoseActor; + + List nodes = new LinkedList(); + + public ServerRotatorTree(Entity parent){ + this.parent = parent; + entityPoseActor = EntityUtils.getPoseActor(parent); + state = RotatorTreeState.INACTIVE; + } + + public void setActive(boolean isActive){ + if(isActive){ + state = RotatorTreeState.ACTIVE; + } else { + state = RotatorTreeState.INACTIVE; + //clear all modifications we've made up to this point + for(RotatorHierarchyNode node : nodes){ + entityPoseActor.getBoneRotator(node.getBone()).getRotation().identity(); + } + } + } + + public void simulate(float deltaTime){ + if(entityPoseActor.modelIsLoaded() && this.state == RotatorTreeState.ACTIVE){ + for(RotatorHierarchyNode node : nodes){ + applyRotatorNode(node); + } + } + } + + public void applyRotatorNode(RotatorHierarchyNode node){ + //apply + String nodeBoneName = node.getBone(); + Quaternionf currentRotation = entityPoseActor.getBoneRotation(nodeBoneName); + for(RotatorConstraint constraint : node.getRotatorContraints()){ + float allowedMarginPitch = constraint.getAllowedMarginPitch(); + float allowedMarginYaw = constraint.getAllowedMarginYaw(); + boolean followsBone = constraint.getFollowsBone(); + boolean followsView = constraint.getFollowsView(); + if(followsBone){ + String parentBone = constraint.getParentBone(); + Quaternionf parentBoneRotation = entityPoseActor.getBoneRotation(parentBone); + // currentRotation. + } + if(followsView){ + ActorBoneRotator currentRotator = entityPoseActor.getBoneRotator(node.getBone()); + //apparently this isn't needed? + //not sure I understand the math on this one + // Vector3d facingVector = CreatureUtils.getFacingVector(parent); + // Vector3f rotationAxis = new Vector3f((float)facingVector.x,(float)facingVector.y,(float)facingVector.z).rotateY((float)Math.PI/2.0f).normalize(); + Vector3f rotationAxis = new Vector3f(1,0,0); + float rotationRaw = 0.0f; + if(parent == Globals.playerEntity){ + rotationRaw = Globals.cameraHandler.getPitch(); + } else { + rotationRaw = ViewUtils.getPitch(parent); + } + float rotation = (float)(rotationRaw * Math.PI / 180.0f); + if(Math.abs(rotation) > constraint.getAllowedMarginPitch()){ + rotation = (float)Math.copySign(constraint.allowedMarginPitch, rotation); + } + currentRotator.getRotation().identity().rotationAxis(rotation, rotationAxis); + } + } + //recurse to children + // for(RotatorHierarchyNode child : node.getChildren()){ + // applyRotatorNode(child); + // } + } + + public void addRotatorNode(RotatorHierarchyNode node){ + nodes.add(node); + } + + public float calculateYawOfQuat(Quaternionf quat){ + return (float)Math.atan2(2.0*(quat.y*quat.z + quat.w*quat.x), quat.w*quat.w - quat.x*quat.x - quat.y*quat.y + quat.z*quat.z); + } + + public float calculatePitchOfQuat(Quaternionf quat){ + return (float)Math.asin(-2.0*(quat.x*quat.z - quat.w*quat.y)); + } + + public static ServerRotatorTree getServerRotatorTree(Entity parent){ + return (ServerRotatorTree)parent.getData(EntityDataStrings.SERVER_ROTATOR_TREE); + } + +} diff --git a/src/main/java/electrosphere/entity/types/attach/AttachUtils.java b/src/main/java/electrosphere/entity/types/attach/AttachUtils.java index 20ae9ca9..7e7ee556 100644 --- a/src/main/java/electrosphere/entity/types/attach/AttachUtils.java +++ b/src/main/java/electrosphere/entity/types/attach/AttachUtils.java @@ -8,6 +8,8 @@ import electrosphere.entity.EntityUtils; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.renderer.Model; import electrosphere.renderer.actor.Actor; +import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.datacell.utils.ServerEntityTagUtils; import java.util.LinkedList; import java.util.List; @@ -24,8 +26,24 @@ import org.joml.Vector3f; public class AttachUtils { - public static void attachEntityToEntityAtBone(Entity parent, Entity toAttach, String boneName, Quaternionf rotation){ - Globals.entityManager.registerEntityToTag(toAttach, EntityTags.BONE_ATTACHED); + public static void serverAttachEntityToEntityAtBone(Entity parent, Entity toAttach, String boneName, Quaternionf rotation){ + ServerEntityTagUtils.attachTagToEntity(toAttach, EntityTags.BONE_ATTACHED); + toAttach.putData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED, true); + toAttach.putData(EntityDataStrings.ATTACH_PARENT, parent); + toAttach.putData(EntityDataStrings.ATTACH_TARGET_BONE, boneName); + toAttach.putData(EntityDataStrings.ATTACH_ROTATION_OFFSET, rotation); + if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){ + getChildrenList(parent).add(toAttach); + } else { + LinkedList childrenEntities = new LinkedList (); + childrenEntities.add(toAttach); + parent.putData(EntityDataStrings.ATTACH_CHILDREN_LIST, childrenEntities); + } + } + + + public static void clientAttachEntityToEntityAtBone(Entity parent, Entity toAttach, String boneName, Quaternionf rotation){ + Globals.clientSceneWrapper.getScene().registerEntityToTag(toAttach, EntityTags.BONE_ATTACHED); toAttach.putData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED, true); toAttach.putData(EntityDataStrings.ATTACH_PARENT, parent); toAttach.putData(EntityDataStrings.ATTACH_TARGET_BONE, boneName); @@ -39,8 +57,41 @@ public class AttachUtils { } } - public static void updateAttachedEntityPositions(){ - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.BONE_ATTACHED)){ + public static void serverUpdateAttachedEntityPositions(ServerDataCell cell){ + for(Entity currentEntity : cell.getScene().getEntitiesWithTag(EntityTags.BONE_ATTACHED)){ + Entity parent; + if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){ + String targetBone; + if((targetBone = (String)currentEntity.getData(EntityDataStrings.ATTACH_TARGET_BONE))!=null){ + Actor parentActor = EntityUtils.getActor(parent); + //get offset rotation + Quaternionf offsetRotation = getRotationOffset(currentEntity); + //transform bone space + Vector3d position = new Vector3d(parentActor.getBonePosition(targetBone)); + position = position.mul(((Vector3f)EntityUtils.getScale(parent))); + Quaternionf rotation = EntityUtils.getRotation(parent); + position = position.rotate(new Quaterniond(rotation.x,rotation.y,rotation.z,rotation.w)); + //transform worldspace + position.add(new Vector3d(EntityUtils.getPosition(parent))); + //set + EntityUtils.getPosition(currentEntity).set(position); + //set rotation +// Quaternionf rotation = parentActor.getBoneRotation(targetBone); +// EntityUtils.getRotation(currentEntity).set(rotation).normalize(); + Vector3d facingAngle = CreatureUtils.getFacingVector(parent); + //calculate rotation of model + EntityUtils.getRotation(currentEntity) + .rotationTo(new Vector3f(0,0,1), new Vector3f((float)facingAngle.x,(float)facingAngle.y,(float)facingAngle.z)) + .mul(parentActor.getBoneRotation(targetBone)) + .mul(offsetRotation) + .normalize(); + } + } + } + } + + public static void clientUpdateAttachedEntityPositions(){ + for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.BONE_ATTACHED)){ Entity parent; if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){ String targetBone; @@ -72,8 +123,18 @@ public class AttachUtils { } } - public static void detatchEntityFromEntityAtBone(Entity parent, Entity toAttach){ - Globals.entityManager.registerEntityToTag(toAttach, EntityTags.BONE_ATTACHED); + public static void serverDetatchEntityFromEntityAtBone(Entity parent, Entity toAttach){ + ServerEntityTagUtils.removeTagFromEntity(toAttach, EntityTags.BONE_ATTACHED); + toAttach.removeData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED); + toAttach.removeData(EntityDataStrings.ATTACH_PARENT); + toAttach.removeData(EntityDataStrings.ATTACH_TARGET_BONE); + if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){ + getChildrenList(parent).remove(toAttach); + } + } + + public static void clientDetatchEntityFromEntityAtBone(Entity parent, Entity toAttach){ + Globals.clientSceneWrapper.getScene().removeEntityFromTag(toAttach, EntityTags.BONE_ATTACHED); toAttach.removeData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED); toAttach.removeData(EntityDataStrings.ATTACH_PARENT); toAttach.removeData(EntityDataStrings.ATTACH_TARGET_BONE); diff --git a/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java b/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java index 64b23e45..419102b6 100644 --- a/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java +++ b/src/main/java/electrosphere/entity/types/camera/CameraEntityUtils.java @@ -2,6 +2,7 @@ package electrosphere.entity.types.camera; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.BehaviorTree; @@ -19,8 +20,7 @@ public class CameraEntityUtils { public static Entity spawnBasicCameraEntity(Vector3f center, Vector3f eye){ - Entity rVal = new Entity(); - Globals.entityManager.registerEntity(rVal); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_TYPE, EntityDataStrings.DATA_STRING_CAMERA_TYPE_BASIC); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_CENTER, center); rVal.putData(EntityDataStrings .DATA_STRING_CAMERA_EYE, eye); @@ -32,8 +32,7 @@ public class CameraEntityUtils { } public static Entity spawnEntityTrackingCameraEntity(Vector3f center, Vector3f eye, Entity toTrack){ - Entity rVal = new Entity(); - Globals.entityManager.registerEntity(rVal); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_TYPE, EntityDataStrings.DATA_STRING_CAMERA_TYPE_ORBIT); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_CENTER, center); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_EYE, eye); @@ -50,13 +49,12 @@ public class CameraEntityUtils { } } }; - Globals.entityManager.registerBehaviorTree(entityTrackingTree); + Globals.clientScene.registerBehaviorTree(entityTrackingTree); return rVal; } public static Entity spawnPlayerEntityTrackingCameraEntity(Vector3f center, Vector3f eye){ - Entity rVal = new Entity(); - Globals.entityManager.registerEntity(rVal); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_TYPE, EntityDataStrings.DATA_STRING_CAMERA_TYPE_ORBIT); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_CENTER, center); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_EYE, eye); @@ -73,13 +71,12 @@ public class CameraEntityUtils { } } }; - Globals.entityManager.registerBehaviorTree(entityTrackingTree); + Globals.clientScene.registerBehaviorTree(entityTrackingTree); return rVal; } public static Entity spawnPlayerEntityAirplaneTrackingCameraEntity(Vector3f center, Vector3f eye){ - Entity rVal = new Entity(); - Globals.entityManager.registerEntity(rVal); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_TYPE, EntityDataStrings.DATA_STRING_CAMERA_TYPE_ORBIT); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_CENTER, center); rVal.putData(EntityDataStrings.DATA_STRING_CAMERA_EYE, eye); @@ -96,7 +93,7 @@ public class CameraEntityUtils { } } }; - Globals.entityManager.registerBehaviorTree(entityTrackingTree); + Globals.clientScene.registerBehaviorTree(entityTrackingTree); return rVal; } @@ -154,7 +151,7 @@ public class CameraEntityUtils { public static void destroyCameraEntity(Entity e){ if(e != null){ - Globals.entityManager.deregisterEntity(e); + Globals.clientScene.deregisterEntity(e); } } diff --git a/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java b/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java index ab869950..a9bce4f1 100644 --- a/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java +++ b/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java @@ -4,11 +4,13 @@ import electrosphere.collision.dispatch.CollisionObject; import electrosphere.collision.shapes.CylinderShape; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.attach.AttachUtils; import electrosphere.game.collision.PhysicsUtils; import electrosphere.game.collision.collidable.Collidable; +import electrosphere.server.datacell.Realm; import org.joml.Matrix4f; import org.joml.Quaternionf; @@ -21,8 +23,8 @@ import org.joml.Vector3f; */ public class CollisionObjUtils { - public static Entity spawnCollisionPlane(Vector3f scale, Vector3f position, Quaternionf rotation){ - Entity rVal = new Entity(); + public static Entity clientSpawnCollisionPlane(Vector3f scale, Vector3f position, Quaternionf rotation){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); float mass = 1.0f; @@ -33,8 +35,39 @@ public class CollisionObjUtils { 1.0f); planeObject.setWorldTransform(new electrosphere.linearmath.Transform(planeTransform)); Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); - Globals.collisionEngine.registerCollisionObject(planeObject, collidable); - Globals.collisionEngine.registerStructurePhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(planeObject, collidable); + Globals.clientSceneWrapper.getCollisionEngine().registerStructurePhysicsEntity(rVal); + + rVal.putData(EntityDataStrings.COLLISION_ENTITY_TYPE_PLANE, true); + rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(position.x,position.y,position.z)); + rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, rotation); + rVal.putData(EntityDataStrings.DATA_STRING_SCALE, scale); + rVal.putData(EntityDataStrings.COLLISION_ENTITY_COLLISION_OBJECT, planeObject); + rVal.putData(EntityDataStrings.COLLISION_ENTITY_COLLIDABLE, collidable); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://scienceworld.wolfram.com/physics/MomentofInertiaCylinder.html + Matrix4f inertiaTensor = new Matrix4f().zero(); + rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor); + rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); + + return rVal; + } + + public static Entity serverSpawnCollisionPlane(Realm realm, Vector3f scale, Vector3f position, Quaternionf rotation){ + Entity rVal = EntityCreationUtils.createServerEntity(realm, new Vector3d(position)); + + float mass = 1.0f; + + CollisionObject planeObject = PhysicsUtils.getPlaneObject(scale); + javax.vecmath.Matrix4f planeTransform = new javax.vecmath.Matrix4f( + PhysicsUtils.jomlToVecmathQuaternionf(rotation), + PhysicsUtils.jomlToVecmathVector3f(position), + 1.0f); + planeObject.setWorldTransform(new electrosphere.linearmath.Transform(planeTransform)); + Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); + realm.getCollisionEngine().registerCollisionObject(planeObject, collidable); + realm.getCollisionEngine().registerStructurePhysicsEntity(rVal); rVal.putData(EntityDataStrings.COLLISION_ENTITY_TYPE_PLANE, true); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(position.x,position.y,position.z)); @@ -49,13 +82,12 @@ public class CollisionObjUtils { rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor); rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); - Globals.entityManager.registerEntity(rVal); return rVal; } - public static Entity spawnCollisionCube(Vector3f scale, Vector3f position, Quaternionf rotation){ - Entity rVal = new Entity(); + public static Entity clientSpawnCollisionCube(Vector3f scale, Vector3f position, Quaternionf rotation){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); float mass = 1.0f; @@ -66,8 +98,39 @@ public class CollisionObjUtils { 1.0f); cubeObject.setWorldTransform(new electrosphere.linearmath.Transform(planeTransform)); Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); - Globals.collisionEngine.registerCollisionObject(cubeObject, collidable); - Globals.collisionEngine.registerStructurePhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(cubeObject, collidable); + Globals.clientSceneWrapper.getCollisionEngine().registerStructurePhysicsEntity(rVal); + + rVal.putData(EntityDataStrings.COLLISION_ENTITY_TYPE_CUBE, true); + rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(position.x,position.y,position.z)); + rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, rotation); + rVal.putData(EntityDataStrings.DATA_STRING_SCALE, scale); + rVal.putData(EntityDataStrings.COLLISION_ENTITY_COLLISION_OBJECT, cubeObject); + rVal.putData(EntityDataStrings.COLLISION_ENTITY_COLLIDABLE, collidable); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://hepweb.ucsd.edu/ph110b/110b_notes/node26.html + Matrix4f inertiaTensor = new Matrix4f().identity().scale(mass * scale.x * scale.x / 6.0f).m33(1); + rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); + + return rVal; + } + + public static Entity serverSpawnCollisionCube(Realm realm, Vector3f scale, Vector3f position, Quaternionf rotation){ + Entity rVal = EntityCreationUtils.createServerEntity(realm, new Vector3d(position)); + + float mass = 1.0f; + + CollisionObject cubeObject = PhysicsUtils.getCubeObject(scale); + javax.vecmath.Matrix4f planeTransform = new javax.vecmath.Matrix4f( + PhysicsUtils.jomlToVecmathQuaternionf(rotation), + PhysicsUtils.jomlToVecmathVector3f(position), + 1.0f); + cubeObject.setWorldTransform(new electrosphere.linearmath.Transform(planeTransform)); + Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); + realm.getCollisionEngine().registerCollisionObject(cubeObject, collidable); + realm.getCollisionEngine().registerStructurePhysicsEntity(rVal); rVal.putData(EntityDataStrings.COLLISION_ENTITY_TYPE_CUBE, true); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(position.x,position.y,position.z)); @@ -82,12 +145,11 @@ public class CollisionObjUtils { rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); - Globals.entityManager.registerEntity(rVal); return rVal; } - public static Entity spawnCollisionCylinder(Vector3f scale, Vector3f position, Quaternionf rotation){ - Entity rVal = new Entity(); + public static Entity clientSpawnCollisionCylinder(Vector3f scale, Vector3f position, Quaternionf rotation){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); float mass = 1.0f; @@ -98,8 +160,42 @@ public class CollisionObjUtils { 1.0f); cubeObject.setWorldTransform(new electrosphere.linearmath.Transform(planeTransform)); Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); - Globals.collisionEngine.registerCollisionObject(cubeObject, collidable); - Globals.collisionEngine.registerStructurePhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(cubeObject, collidable); + Globals.clientSceneWrapper.getCollisionEngine().registerStructurePhysicsEntity(rVal); + + rVal.putData(EntityDataStrings.COLLISION_ENTITY_TYPE_CYLINDER, true); + rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(position.x,position.y,position.z)); + rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, rotation); + rVal.putData(EntityDataStrings.DATA_STRING_SCALE, scale); + rVal.putData(EntityDataStrings.COLLISION_ENTITY_COLLISION_OBJECT, cubeObject); + rVal.putData(EntityDataStrings.COLLISION_ENTITY_COLLIDABLE, collidable); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://scienceworld.wolfram.com/physics/MomentofInertiaCylinder.html + Matrix4f inertiaTensor = new Matrix4f(); + inertiaTensor.m00(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m11(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m22(mass * scale.x * scale.x / 2.0f); + rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); + + return rVal; + } + + public static Entity serverSpawnCollisionCylinder(Realm realm, Vector3f scale, Vector3f position, Quaternionf rotation){ + Entity rVal = EntityCreationUtils.createServerEntity(realm, new Vector3d(position)); + + float mass = 1.0f; + + CollisionObject cubeObject = PhysicsUtils.getCylinderObject(scale); + javax.vecmath.Matrix4f planeTransform = new javax.vecmath.Matrix4f( + PhysicsUtils.jomlToVecmathQuaternionf(rotation), + PhysicsUtils.jomlToVecmathVector3f(position), + 1.0f); + cubeObject.setWorldTransform(new electrosphere.linearmath.Transform(planeTransform)); + Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); + realm.getCollisionEngine().registerCollisionObject(cubeObject, collidable); + realm.getCollisionEngine().registerStructurePhysicsEntity(rVal); rVal.putData(EntityDataStrings.COLLISION_ENTITY_TYPE_CYLINDER, true); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(position.x,position.y,position.z)); @@ -117,13 +213,28 @@ public class CollisionObjUtils { rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); - Globals.entityManager.registerEntity(rVal); return rVal; } - public static Entity attachCollisionPlane(Vector3f scale, Vector3f position, Quaternionf rotation, Entity parent){ - Entity rVal = spawnCollisionPlane(scale, position, rotation); + public static Entity clientAttachCollisionPlane(Vector3f scale, Vector3f position, Quaternionf rotation, Entity parent){ + Entity rVal = clientSpawnCollisionPlane(scale, position, rotation); + + AttachUtils.attachEntityToEntity(parent, rVal); + + float mass = 1.0f; + parent.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://scienceworld.wolfram.com/physics/MomentofInertiaCylinder.html + Matrix4f inertiaTensor = new Matrix4f().zero(); + parent.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor); + + return rVal; + } + + public static Entity serverAttachCollisionPlane(Vector3f scale, Vector3f position, Quaternionf rotation, Entity parent){ + Realm parentRealm = Globals.realmManager.getEntityRealm(parent); + Entity rVal = serverSpawnCollisionPlane(parentRealm, scale, position, rotation); AttachUtils.attachEntityToEntity(parent, rVal); @@ -137,8 +248,24 @@ public class CollisionObjUtils { return rVal; } - public static Entity attachCollisionCube(Vector3f scale, Vector3f position, Quaternionf rotation, Entity parent){ - Entity rVal = spawnCollisionCube(scale, position, rotation); + public static Entity clientAttachCollisionCube(Vector3f scale, Vector3f position, Quaternionf rotation, Entity parent){ + Entity rVal = clientSpawnCollisionCube(scale, position, rotation); + + AttachUtils.attachEntityToEntity(parent, rVal); + + float mass = 1.0f; + parent.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://hepweb.ucsd.edu/ph110b/110b_notes/node26.html + Matrix4f inertiaTensor = new Matrix4f().identity().scale(mass * scale.x * scale.x / 6.0f).m33(1); + parent.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + + return rVal; + } + + public static Entity serverAttachCollisionCube(Vector3f scale, Vector3f position, Quaternionf rotation, Entity parent){ + Realm parentRealm = Globals.realmManager.getEntityRealm(parent); + Entity rVal = serverSpawnCollisionCube(parentRealm, scale, position, rotation); AttachUtils.attachEntityToEntity(parent, rVal); @@ -152,8 +279,27 @@ public class CollisionObjUtils { return rVal; } - public static Entity attachCollisionCylinder(Vector3f scale, Vector3f position, Quaternionf rotation, Entity parent){ - Entity rVal = spawnCollisionCylinder(scale, position, rotation); + public static Entity clientAttachCollisionCylinder(Vector3f scale, Vector3f position, Quaternionf rotation, Entity parent){ + Entity rVal = clientSpawnCollisionCylinder(scale, position, rotation); + + AttachUtils.attachEntityToEntity(parent, rVal); + + float mass = 1.0f; + parent.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://scienceworld.wolfram.com/physics/MomentofInertiaCylinder.html + Matrix4f inertiaTensor = new Matrix4f(); + inertiaTensor.m00(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m11(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m22(mass * scale.x * scale.x / 2.0f); + parent.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + + return rVal; + } + + public static Entity serverAttachCollisionCylinder(Vector3f scale, Vector3f position, Quaternionf rotation, Entity parent){ + Realm parentRealm = Globals.realmManager.getEntityRealm(parent); + Entity rVal = serverSpawnCollisionCylinder(parentRealm, scale, position, rotation); AttachUtils.attachEntityToEntity(parent, rVal); @@ -177,13 +323,45 @@ public class CollisionObjUtils { * @param mass The mass of the collidable * @param collidableType The type of collidable we are attaching. For instance, "Terrain", "Creature", "Item", etc. Refer to Collidable class for options. */ - public static void attachCollisionObjectToEntity(Entity entity, CollisionObject collisionObject, float mass, String collidableType){ + public static void clientAttachCollisionObjectToEntity(Entity entity, CollisionObject collisionObject, float mass, String collidableType){ Vector3d position = EntityUtils.getPosition(entity); Vector3f scale = EntityUtils.getScale(entity); Collidable collidable = new Collidable(entity, collidableType); - Globals.collisionEngine.registerCollisionObject(collisionObject, collidable); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(collisionObject, collidable); - Globals.collisionEngine.registerPhysicsEntity(entity); + Globals.clientSceneWrapper.getCollisionEngine().registerPhysicsEntity(entity); + entity.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, collisionObject); + + //update world transform of collision object + positionCharacter(entity,position); + + entity.putData(EntityDataStrings.COLLISION_ENTITY_COLLISION_OBJECT, collisionObject); + entity.putData(EntityDataStrings.COLLISION_ENTITY_COLLIDABLE, collidable); + entity.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://scienceworld.wolfram.com/physics/MomentofInertiaCylinder.html + Matrix4f inertiaTensor = new Matrix4f(); + inertiaTensor.m00(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m11(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m22(mass * scale.x * scale.x / 2.0f); + entity.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + } + + /** + * Attach a collision object to a provided entity + * @param entity The entity to attach a collision object to + * @param collisionObject The jBulletF collision object to attach to the entity + * @param mass The mass of the collidable + * @param collidableType The type of collidable we are attaching. For instance, "Terrain", "Creature", "Item", etc. Refer to Collidable class for options. + */ + public static void serverAttachCollisionObjectToEntity(Entity entity, CollisionObject collisionObject, float mass, String collidableType){ + Vector3d position = EntityUtils.getPosition(entity); + Vector3f scale = EntityUtils.getScale(entity); + Collidable collidable = new Collidable(entity, collidableType); + Realm realm = Globals.realmManager.getEntityRealm(entity); + realm.getCollisionEngine().registerCollisionObject(collisionObject, collidable); + + realm.getCollisionEngine().registerPhysicsEntity(entity); entity.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, collisionObject); //update world transform of collision object diff --git a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java index 376702ae..323fd8f3 100644 --- a/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java +++ b/src/main/java/electrosphere/entity/types/creature/CreatureUtils.java @@ -5,32 +5,43 @@ import electrosphere.dynamics.RigidBody; import electrosphere.engine.Globals; import electrosphere.engine.Main; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; +import electrosphere.entity.Scene; import electrosphere.entity.state.movement.AirplaneMovementTree; import electrosphere.entity.state.movement.FallTree; import electrosphere.entity.state.movement.GroundMovementTree; +import electrosphere.entity.state.movement.ServerGroundMovementTree; import electrosphere.entity.state.movement.JumpTree; +import electrosphere.entity.state.movement.ServerFallTree; +import electrosphere.entity.state.movement.ServerJumpTree; +import electrosphere.entity.state.movement.ServerSprintTree; import electrosphere.entity.types.hitbox.HitboxData; import electrosphere.entity.types.hitbox.HitboxUtils; import electrosphere.game.data.creature.type.CreatureType; import electrosphere.entity.state.BehaviorTree; -import electrosphere.entity.state.IdleTree; import electrosphere.entity.state.attack.AttackTree; +import electrosphere.entity.state.attack.ServerAttackTree; import electrosphere.entity.state.attack.ShooterTree; -import electrosphere.entity.state.collidable.CollidableTree; +import electrosphere.entity.state.collidable.ClientCollidableTree; +import electrosphere.entity.state.collidable.ServerCollidableTree; import electrosphere.entity.state.equip.EquipState; import electrosphere.entity.state.gravity.GravityTree; +import electrosphere.entity.state.gravity.ServerGravityTree; +import electrosphere.entity.state.idle.IdleTree; import electrosphere.entity.state.inventory.InventoryState; import electrosphere.entity.state.inventory.InventoryUtils; import electrosphere.entity.state.inventory.RelationalInventoryState; +import electrosphere.entity.state.inventory.ServerInventoryState; import electrosphere.entity.state.inventory.UnrelationalInventoryState; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.state.life.LifeState; import electrosphere.entity.state.movement.SprintTree; import electrosphere.entity.state.rotator.RotatorHierarchyNode; import electrosphere.entity.state.rotator.RotatorTree; +import electrosphere.entity.state.rotator.ServerRotatorTree; import electrosphere.game.collision.PhysicsUtils; import electrosphere.game.collision.collidable.Collidable; import electrosphere.game.data.creature.type.CollidableTemplate; @@ -59,7 +70,14 @@ import electrosphere.renderer.actor.ActorStaticMorph; import electrosphere.renderer.actor.ActorUtils; import electrosphere.renderer.light.PointLight; import electrosphere.renderer.loading.ModelLoader; +import electrosphere.server.datacell.Realm; import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.datacell.utils.DataCellSearchUtils; +import electrosphere.server.datacell.utils.EntityLookupUtils; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; +import electrosphere.server.datacell.utils.ServerEntityTagUtils; +import electrosphere.server.poseactor.PoseActor; +import electrosphere.server.poseactor.PoseActorUtils; import electrosphere.util.Utilities; import java.util.LinkedList; @@ -94,21 +112,54 @@ public class CreatureUtils { // Globals.entityManager.registerMoveableEntity(rVal); // return rVal; // } + + // /** + // * Spawns a server-side creature entity + // * @param type The type of creature + // * @param template The creature template if applicable + // * @param realm The realm to spawn the creature in + // * @param position The position to place the creature at + // * @return The creature entity + // */ + // public static Entity serverSpawnCreature(String type, CreatureTemplate template, Realm realm, Vector3d position){ + // Entity rVal = EntityCreationUtils.createServerEntity(realm, position); + // spawnBasicCreature(rVal, type, template, true); + // return rVal; + // } + + // /** + // * Spawns a client-side creature entity + // * @param type The type of creature + // * @param template The creature template if applicable + // * @return The creature entity + // */ + // public static Entity clientSpawnCreature(String type, CreatureTemplate template){ + // Entity rVal = EntityCreationUtils.createClientEntity(); + // spawnBasicCreature(rVal, type, template, false); + // return rVal; + // } - public static Entity spawnBasicCreature(String type, CreatureTemplate template){ + /** + * Spawns a client-side creature entity + * @param type The type of creature + * @param template The creature template if applicable + * @return The creature entity + */ + public static Entity clientSpawnBasicCreature(String type, CreatureTemplate template){ CreatureType rawType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(type); - Entity rVal = EntityUtils.spawnDrawableEntity(rawType.getModelPath()); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath()); Actor creatureActor = EntityUtils.getActor(rVal); for(HitboxData hitboxdata : rawType.getHitboxes()){ List hitboxList = new LinkedList(); List hurtboxList = new LinkedList(); if(hitboxdata.getType().equals("hit")){ - Entity hitbox = HitboxUtils.spawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); - Globals.hitboxManager.registerHitbox(hitbox); + Entity hitbox = HitboxUtils.clientSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); + Globals.clientHitboxManager.registerHitbox(hitbox); hitboxList.add(hitbox); } else if(hitboxdata.getType().equals("hurt")){ - Entity hurtbox = HitboxUtils.spawnRegularHurtbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); - Globals.hitboxManager.registerHitbox(hurtbox); + Entity hurtbox = HitboxUtils.clientSpawnRegularHurtbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); + Globals.clientHitboxManager.registerHitbox(hurtbox); hurtboxList.add(hurtbox); } rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST, hitboxList); @@ -125,12 +176,12 @@ public class CreatureUtils { case "CYLINDER": { rigidBody = PhysicsUtils.getCylinderObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); collidable = new Collidable(rVal, Collidable.TYPE_CREATURE); - CollidableTree tree = new CollidableTree(rVal,collidable,rigidBody); + ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody); rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - rVal.putData(EntityDataStrings.COLLIDABLE_TREE, tree); + rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree); scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); @@ -142,20 +193,20 @@ public class CreatureUtils { inertiaTensor.m22(mass * scale.x * scale.x / 2.0f); rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); - Globals.collisionEngine.registerPhysicsEntity(rVal); - Globals.collisionEngine.registerDynamicPhysicsEntity(rVal); - Globals.collisionEngine.registerCollisionObject(rigidBody, collidable); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.COLLIDABLE); + Globals.clientSceneWrapper.getCollisionEngine().registerPhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE); } break; case "CUBE": { rigidBody = PhysicsUtils.getCubeObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); collidable = new Collidable(rVal, Collidable.TYPE_CREATURE); - CollidableTree tree = new CollidableTree(rVal,collidable,rigidBody); + ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody); rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - rVal.putData(EntityDataStrings.COLLIDABLE_TREE, tree); + rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree); scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); @@ -164,10 +215,10 @@ public class CreatureUtils { inertiaTensor = new Matrix4f().identity().scale(mass * scale.x * scale.x / 6.0f).m33(1); rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); - Globals.collisionEngine.registerPhysicsEntity(rVal); - Globals.collisionEngine.registerDynamicPhysicsEntity(rVal); - Globals.collisionEngine.registerCollisionObject(rigidBody, collidable); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.COLLIDABLE); + Globals.clientSceneWrapper.getCollisionEngine().registerPhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE); } break; } } @@ -207,18 +258,18 @@ public class CreatureUtils { } sprintTree.setGroundMovementTree(moveTree); moveTree.setSprintTree(sprintTree); - rVal.putData(EntityDataStrings.SPRINT_TREE,sprintTree); - Globals.entityManager.registerBehaviorTree(sprintTree); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.SPRINTABLE); + rVal.putData(EntityDataStrings.CLIENT_SPRINT_TREE,sprintTree); + Globals.clientScene.registerBehaviorTree(sprintTree); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.SPRINTABLE); } //round out end of move system - rVal.putData(EntityDataStrings.DATA_STRING_MOVEMENT_BT, moveTree); + rVal.putData(EntityDataStrings.CLIENT_MOVEMENT_BT, moveTree); CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,0)); rVal.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, groundMovementSystem.getMaxVelocity()); rVal.putData(EntityDataStrings.DATA_STRING_ACCELERATION, groundMovementSystem.getAcceleration()); rVal.putData(EntityDataStrings.DATA_STRING_VELOCITY, 0f); - Globals.entityManager.registerBehaviorTree(moveTree); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.MOVEABLE); + Globals.clientScene.registerBehaviorTree(moveTree); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.MOVEABLE); break; // // Jump @@ -228,14 +279,14 @@ public class CreatureUtils { if(jumpMovementSystem.getAnimationJump() != null){ jumpTree.setAnimationJump(jumpMovementSystem.getAnimationJump().getName()); } - if(CreatureUtils.getEntityMovementTree(rVal) != null && CreatureUtils.getEntityMovementTree(rVal) instanceof GroundMovementTree){ - ((GroundMovementTree)CreatureUtils.getEntityMovementTree(rVal)).setJumpTree(jumpTree); + if(CreatureUtils.clientGetEntityMovementTree(rVal) != null && CreatureUtils.clientGetEntityMovementTree(rVal) instanceof GroundMovementTree){ + ((GroundMovementTree)CreatureUtils.clientGetEntityMovementTree(rVal)).setClientJumpTree(jumpTree); } if(FallTree.getFallTree(rVal)!=null){ FallTree.getFallTree(rVal).setJumpTree(jumpTree); } - rVal.putData(EntityDataStrings.JUMP_TREE, jumpTree); - Globals.entityManager.registerBehaviorTree(jumpTree); + rVal.putData(EntityDataStrings.CLIENT_JUMP_TREE, jumpTree); + Globals.clientScene.registerBehaviorTree(jumpTree); break; // // Falling @@ -248,14 +299,14 @@ public class CreatureUtils { if(fallMovementSystem.getAnimationLand()!=null){ fallTree.setAnimationLand(fallMovementSystem.getAnimationLand().getName()); } - if(CreatureUtils.getEntityMovementTree(rVal) != null && CreatureUtils.getEntityMovementTree(rVal) instanceof GroundMovementTree){ - ((GroundMovementTree)CreatureUtils.getEntityMovementTree(rVal)).setFallTree(fallTree); + if(CreatureUtils.clientGetEntityMovementTree(rVal) != null && CreatureUtils.clientGetEntityMovementTree(rVal) instanceof GroundMovementTree){ + ((GroundMovementTree)CreatureUtils.clientGetEntityMovementTree(rVal)).setClientFallTree(fallTree); } - if(JumpTree.getJumpTree(rVal)!=null){ - fallTree.setJumpTree(JumpTree.getJumpTree(rVal)); + if(JumpTree.getClientJumpTree(rVal)!=null){ + fallTree.setJumpTree(JumpTree.getClientJumpTree(rVal)); } rVal.putData(EntityDataStrings.FALL_TREE, fallTree); - Globals.entityManager.registerBehaviorTree(fallTree); + Globals.clientScene.registerBehaviorTree(fallTree); break; // // Airplane @@ -270,10 +321,10 @@ public class CreatureUtils { airplaneMovementTree.setMinimumVelocity(airplaneMovementSystem.getMinVelocity()); airplaneMovementTree.setMaxRotationSpeed(airplaneMovementSystem.getMaxRotationSpeed()); //register misc stuff - rVal.putData(EntityDataStrings.DATA_STRING_MOVEMENT_BT, airplaneMovementTree); + rVal.putData(EntityDataStrings.CLIENT_MOVEMENT_BT, airplaneMovementTree); CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,0)); - Globals.entityManager.registerBehaviorTree(airplaneMovementTree); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.MOVEABLE); + Globals.clientScene.registerBehaviorTree(airplaneMovementTree); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.MOVEABLE); } break; } } @@ -288,10 +339,10 @@ public class CreatureUtils { break; case "ATTACKER": AttackTree attackTree = new AttackTree(rVal); - rVal.putData(EntityDataStrings.ATTACK_TREE, attackTree); + rVal.putData(EntityDataStrings.CLIENT_ATTACK_TREE, attackTree); rVal.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, null); - Globals.entityManager.registerBehaviorTree(attackTree); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.ATTACKER); + Globals.clientScene.registerBehaviorTree(attackTree); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.ATTACKER); //add all attack moves if(rawType.getAttackMoves() != null && rawType.getAttackMoves().size() > 0){ for(AttackMove attackMove : rawType.getAttackMoves()){ @@ -310,23 +361,23 @@ public class CreatureUtils { case "SHOOTER": { ShooterTree shooterTree = new ShooterTree(rVal); ShooterTree.setShooterTree(rVal, shooterTree); - Globals.entityManager.registerBehaviorTree(shooterTree); + Globals.clientScene.registerBehaviorTree(shooterTree); } break; case "GRAVITY": Collidable collidable = (Collidable)rVal.getData(EntityDataStrings.PHYSICS_COLLIDABLE); CollisionObject collisionObject = (CollisionObject)rVal.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); GravityTree gravityTree = new GravityTree(rVal,collidable,collisionObject,30); -// gravityTree.setCollisionObject(collisionObject, collidable); + // gravityTree.setCollisionObject(collisionObject, collidable); rVal.putData(EntityDataStrings.GRAVITY_ENTITY, true); - rVal.putData(EntityDataStrings.GRAVITY_TREE, gravityTree); - Globals.entityManager.registerBehaviorTree(gravityTree); + rVal.putData(EntityDataStrings.CLIENT_GRAVITY_TREE, gravityTree); + Globals.clientScene.registerBehaviorTree(gravityTree); break; case "TARGETABLE": - Globals.entityManager.registerEntityToTag(rVal, EntityTags.TARGETABLE); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.TARGETABLE); break; case "INVENTORY": rVal.putData(EntityDataStrings.NATURAL_INVENTORY,UnrelationalInventoryState.createUnrelationalInventory(10)); - InventoryUtils.setInventoryState(rVal, InventoryState.createInventoryState(rVal)); + InventoryUtils.clientSetInventoryState(rVal, InventoryState.clientCreateInventoryState(rVal)); break; case "OUTLINE": rVal.putData(EntityDataStrings.DRAW_OUTLINE, true); @@ -418,15 +469,366 @@ public class CreatureUtils { } rotatorTree.addRotatorNode(hierarchyNode); } - rVal.putData(EntityDataStrings.ROTATOR_TREE, rotatorTree); - Globals.entityManager.registerBehaviorTree(rotatorTree); + rVal.putData(EntityDataStrings.CLIENT_ROTATOR_TREE, rotatorTree); + Globals.clientScene.registerBehaviorTree(rotatorTree); } //add health system rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem())); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.LIFE_STATE); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.LIFE_STATE); //idle tree & generic stuff all creatures have rVal.putData(EntityDataStrings.IDLE_TREE, new IdleTree(rVal)); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.CREATURE); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.CREATURE); + rVal.putData(EntityDataStrings.DATA_STRING_CREATURE_IS_CREATURE, true); + rVal.putData(EntityDataStrings.DATA_STRING_CREATURE_TYPE, type); + CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,1)); + rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); + return rVal; + } + + + /** + * Spawns a server-side creature + * @param realm The realm to spawn the creature in + * @param position The position of the creature in that realm + * @param type The type of creature + * @param template The creature template to use + * @return The creature entity + */ + public static Entity serverSpawnBasicCreature(Realm realm, Vector3d position, String type, CreatureTemplate template){ + CreatureType rawType = Globals.gameConfigCurrent.getCreatureTypeLoader().getCreature(type); + Entity rVal = EntityCreationUtils.createServerEntity(realm, position); + EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath()); + + PoseActor creatureActor = EntityUtils.getPoseActor(rVal); + for(HitboxData hitboxdata : rawType.getHitboxes()){ + List hitboxList = new LinkedList(); + List hurtboxList = new LinkedList(); + if(hitboxdata.getType().equals("hit")){ + Entity hitbox = HitboxUtils.serverSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); + realm.getHitboxManager().registerHitbox(hitbox); + hitboxList.add(hitbox); + } else if(hitboxdata.getType().equals("hurt")){ + Entity hurtbox = HitboxUtils.serverSpawnRegularHurtbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); + realm.getHitboxManager().registerHitbox(hurtbox); + hurtboxList.add(hurtbox); + } + rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST, hitboxList); + rVal.putData(EntityDataStrings.HURTBOX_ASSOCIATED_LIST, hurtboxList); + } + if(rawType.getCollidable() != null){ + CollidableTemplate physicsTemplate = rawType.getCollidable(); + CollisionObject rigidBody; + Collidable collidable; + float mass = 1.0f; + Matrix4f inertiaTensor; + Vector3f scale; + switch(physicsTemplate.getType()){ + case "CYLINDER": { + rigidBody = PhysicsUtils.getCylinderObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); + collidable = new Collidable(rVal, Collidable.TYPE_CREATURE); + ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); + rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); + rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); + rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree); + + scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://scienceworld.wolfram.com/physics/MomentofInertiaCylinder.html + inertiaTensor = new Matrix4f(); + inertiaTensor.m00(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m11(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m22(mass * scale.x * scale.x / 2.0f); + rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + + realm.getCollisionEngine().registerPhysicsEntity(rVal); + realm.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE); + } break; + case "CUBE": { + rigidBody = PhysicsUtils.getCubeObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); + collidable = new Collidable(rVal, Collidable.TYPE_CREATURE); + ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); + rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); + rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); + rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree); + + scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://hepweb.ucsd.edu/ph110b/110b_notes/node26.html + inertiaTensor = new Matrix4f().identity().scale(mass * scale.x * scale.x / 6.0f).m33(1); + rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + + realm.getCollisionEngine().registerPhysicsEntity(rVal); + realm.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE); + } break; + } + } + // + // + // MOVEMENT SYSTEMS + // + // + for(MovementSystem movementSystem : rawType.getMovementSystems()){ + switch(movementSystem.getType()){ + // + // Generic ground + case GroundMovementSystem.GROUND_MOVEMENT_SYSTEM: + GroundMovementSystem groundMovementSystem = (GroundMovementSystem)movementSystem; + ServerGroundMovementTree moveTree = new ServerGroundMovementTree(rVal,CollisionObjUtils.getCollidable(rVal)); + if(groundMovementSystem.getAnimationStartup() != null){ + moveTree.setAnimationStartUp(groundMovementSystem.getAnimationStartup().getName()); + } + if(groundMovementSystem.getAnimationLoop() != null){ + moveTree.setAnimationMain(groundMovementSystem.getAnimationLoop().getName()); + } + if(groundMovementSystem.getAnimationWindDown()!= null){ + moveTree.setAnimationSlowDown(groundMovementSystem.getAnimationWindDown().getName()); + } + //sprint system + if(groundMovementSystem.getSprintSystem() != null){ + SprintSystem sprintSystem = groundMovementSystem.getSprintSystem(); + ServerSprintTree sprintTree = new ServerSprintTree(rVal,sprintSystem.getMaxVelocity(),sprintSystem.getStaminaMax()); + if(sprintSystem.getAnimationStartUp()!= null){ + moveTree.setAnimationSprintStartUp(sprintSystem.getAnimationStartUp().getName()); + } + if(sprintSystem.getAnimationMain()!= null){ + moveTree.setAnimationSprint(sprintSystem.getAnimationMain().getName()); + } + if(sprintSystem.getAnimationWindDown()!= null){ + moveTree.setAnimationSprintWindDown(sprintSystem.getAnimationWindDown().getName()); + } + sprintTree.setServerGroundMovementTree(moveTree); + moveTree.setServerSprintTree(sprintTree); + rVal.putData(EntityDataStrings.SERVER_SPRINT_TREE,sprintTree); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, sprintTree); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.SPRINTABLE); + } + //round out end of move system + rVal.putData(EntityDataStrings.SERVER_MOVEMENT_BT, moveTree); + CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,0)); + rVal.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, groundMovementSystem.getMaxVelocity()); + rVal.putData(EntityDataStrings.DATA_STRING_ACCELERATION, groundMovementSystem.getAcceleration()); + rVal.putData(EntityDataStrings.DATA_STRING_VELOCITY, 0f); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, moveTree); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.MOVEABLE); + break; + // + // Jump + case JumpMovementSystem.JUMP_MOVEMENT_SYSTEM: + JumpMovementSystem jumpMovementSystem = (JumpMovementSystem)movementSystem; + ServerJumpTree jumpTree = new ServerJumpTree(rVal, jumpMovementSystem.getJumpFrames(), jumpMovementSystem.getJumpForce()); + if(jumpMovementSystem.getAnimationJump() != null){ + jumpTree.setAnimationJump(jumpMovementSystem.getAnimationJump().getName()); + } + if(CreatureUtils.serverGetEntityMovementTree(rVal) != null && CreatureUtils.serverGetEntityMovementTree(rVal) instanceof GroundMovementTree){ + ((ServerGroundMovementTree)CreatureUtils.serverGetEntityMovementTree(rVal)).setServerJumpTree(jumpTree); + } + if(ServerFallTree.getFallTree(rVal)!=null){ + ServerFallTree.getFallTree(rVal).setServerJumpTree(jumpTree); + } + rVal.putData(EntityDataStrings.SERVER_JUMP_TREE, jumpTree); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, jumpTree); + break; + // + // Falling + case FallMovementSystem.FALL_MOVEMENT_SYSTEM: + FallMovementSystem fallMovementSystem = (FallMovementSystem)movementSystem; + ServerFallTree fallTree = new ServerFallTree(rVal); + if(fallMovementSystem.getAnimationFall()!=null){ + fallTree.setAnimationFall(fallMovementSystem.getAnimationFall().getName()); + } + if(fallMovementSystem.getAnimationLand()!=null){ + fallTree.setAnimationLand(fallMovementSystem.getAnimationLand().getName()); + } + if(CreatureUtils.serverGetEntityMovementTree(rVal) != null && CreatureUtils.serverGetEntityMovementTree(rVal) instanceof GroundMovementTree){ + ((ServerGroundMovementTree)CreatureUtils.serverGetEntityMovementTree(rVal)).setServerFallTree(fallTree); + } + if(ServerJumpTree.getServerJumpTree(rVal)!=null){ + fallTree.setServerJumpTree(ServerJumpTree.getServerJumpTree(rVal)); + } + rVal.putData(EntityDataStrings.FALL_TREE, fallTree); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, fallTree); + break; + // + // Airplane + case AirplaneMovementSystem.AIRPLANE_MOVEMENT_SYSTEM: { + //construct tree + AirplaneMovementSystem airplaneMovementSystem = (AirplaneMovementSystem) movementSystem; + AirplaneMovementTree airplaneMovementTree = new AirplaneMovementTree(rVal, CollisionObjUtils.getCollidable(rVal)); + //set properties + rVal.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, airplaneMovementSystem.getMaxVelocity()); + rVal.putData(EntityDataStrings.DATA_STRING_ACCELERATION, airplaneMovementSystem.getAcceleration()); + rVal.putData(EntityDataStrings.DATA_STRING_VELOCITY, 0f); + airplaneMovementTree.setMinimumVelocity(airplaneMovementSystem.getMinVelocity()); + airplaneMovementTree.setMaxRotationSpeed(airplaneMovementSystem.getMaxRotationSpeed()); + //register misc stuff + rVal.putData(EntityDataStrings.SERVER_MOVEMENT_BT, airplaneMovementTree); + CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,0)); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, airplaneMovementTree); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.MOVEABLE); + } break; + } + } + if(rawType.getEquipPoints() != null && rawType.getEquipPoints().size() > 0){ + EquipState.setEquipState(rVal, new EquipState(rVal,rawType.getEquipPoints())); + rVal.putData(EntityDataStrings.EQUIP_INVENTORY, RelationalInventoryState.buildRelationalInventoryStateFromEquipList(rawType.getEquipPoints())); + } + for(String token : rawType.getTokens()){ + switch(token){ + case "BLENDER_TRANSFORM": { + PoseActorUtils.applyBlenderTransformer(rVal); + } break; + case "ATTACKER": { + ServerAttackTree attackTree = new ServerAttackTree(rVal); + rVal.putData(EntityDataStrings.SERVER_ATTACK_TREE, attackTree); + rVal.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, null); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, attackTree); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.ATTACKER); + //add all attack moves + if(rawType.getAttackMoves() != null && rawType.getAttackMoves().size() > 0){ + for(AttackMove attackMove : rawType.getAttackMoves()){ + rVal.putData(attackMove.getType(), rawType.getAttackMoveResolver().getMoveset(attackMove.getType())); + // switch(attackMove.getType()){ + // case EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND: + // rVal.putData(EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND, rawType.getAttackMoveResolver().getMoveset(EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND)); + // break; + // case EntityDataStrings.ATTACK_MOVE_TYPE_BOW_TWO_HAND: + // rVal.putData(EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND, rawType.getAttackMoveResolver().getMoveset(EntityDataStrings.ATTACK_MOVE_TYPE_MELEE_SWING_ONE_HAND)); + // break; + // } + } + } + } break; + case "SHOOTER": { + ShooterTree shooterTree = new ShooterTree(rVal); + ShooterTree.setShooterTree(rVal, shooterTree); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, shooterTree); + } break; + case "GRAVITY": { + Collidable collidable = (Collidable)rVal.getData(EntityDataStrings.PHYSICS_COLLIDABLE); + CollisionObject collisionObject = (CollisionObject)rVal.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); + ServerGravityTree gravityTree = new ServerGravityTree(rVal,collidable,collisionObject,30); + // gravityTree.setCollisionObject(collisionObject, collidable); + rVal.putData(EntityDataStrings.GRAVITY_ENTITY, true); + rVal.putData(EntityDataStrings.SERVER_GRAVITY_TREE, gravityTree); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, gravityTree); + } break; + case "TARGETABLE": { + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.TARGETABLE); + } break; + case "INVENTORY": { + rVal.putData(EntityDataStrings.NATURAL_INVENTORY,UnrelationalInventoryState.createUnrelationalInventory(10)); + InventoryUtils.serverSetInventoryState(rVal, ServerInventoryState.serverCreateInventoryState(rVal)); + } break; + case "OUTLINE": { + rVal.putData(EntityDataStrings.DRAW_OUTLINE, true); + } break; + } + } + //variants + if(rawType.getVisualAttributes() != null){ + ActorStaticMorph staticMorph = null; + CreatureTemplate storedTemplate = new CreatureTemplate(rawType.getCreatureId()); + for(VisualAttribute attributeType : rawType.getVisualAttributes()){ + if(attributeType.getType().equals("remesh")){ + if(attributeType.getVariants() != null && attributeType.getVariants().size() > 0){ + AttributeVariant variant = attributeType.getVariants().get(0); + //if the template isn't null, try to find the variant from the template in the variant list + //if the variant is found, set the variable "variant" to the searched for variant + if(template != null && template.getValue(attributeType.getAttributeId()) != null){ + String variantId = template.getValue(attributeType.getAttributeId()).getVariantId(); + for(AttributeVariant searchVariant : attributeType.getVariants()){ + if(searchVariant.getId().equals(variantId)){ + variant = searchVariant; + //if we find the variant, store in on-creature template as well + storedTemplate.putValue(attributeType.getAttributeId(), variantId); + break; + } + } + } + //make sure stored template contains creature data + if(storedTemplate.getValue(attributeType.getAttributeId())==null){ + storedTemplate.putValue(attributeType.getAttributeId(), attributeType.getVariants().get(0).getId()); + } + //TODO: determine if this should be relevant to pose actor + //pretty certain it shouldn't be but you never know + + // rVal.putData(EntityDataStrings.CREATURE_ATTRIBUTE_VARIANT + attributeType.getAttributeId(), variant.getId()); + // Globals.assetManager.addModelPathToQueue(variant.getModel()); + // for(String mesh : variant.getMeshes()){ + // creatureActor.getMeshMask().queueMesh(variant.getModel(), mesh); + // } + } + } + if(attributeType.getType().equals("bone")){ + if(staticMorph == null){ + staticMorph = new ActorStaticMorph(); + creatureActor.setStaticMorph(staticMorph); + } + if(attributeType.getPrimaryBone() != null && staticMorph.getBoneTransforms(attributeType.getPrimaryBone()) == null){ + staticMorph.initBoneTransforms(attributeType.getPrimaryBone()); + //if the template isn't null, set the value of the morph + if(template != null && template.getValue(attributeType.getAttributeId()) != null){ + float templateValue = template.getValue(attributeType.getAttributeId()).getValue(); + staticMorph.updateValue(attributeType.getSubtype(), attributeType.getPrimaryBone(), templateValue); + } + } + if(attributeType.getMirrorBone() != null && staticMorph.getBoneTransforms(attributeType.getMirrorBone()) == null){ + staticMorph.initBoneTransforms(attributeType.getMirrorBone()); + //if the template isn't null, set the value of the morph + if(template != null && template.getValue(attributeType.getAttributeId()) != null){ + float templateValue = template.getValue(attributeType.getAttributeId()).getValue(); + staticMorph.updateValue(attributeType.getSubtype(), attributeType.getMirrorBone(), templateValue); + } + } + //make sure stored template contains creature data + if(template != null && template.getValue(attributeType.getAttributeId()) != null) { + storedTemplate.putValue(attributeType.getAttributeId(), template.getValue(attributeType.getAttributeId()).getValue()); + } else { + float midpoint = (attributeType.getMaxValue() - attributeType.getMinValue())/2.0f + attributeType.getMinValue(); + storedTemplate.putValue(attributeType.getAttributeId(), midpoint); + } + } + } + //set race + storedTemplate.creatureType = rawType.getCreatureId(); + //store template on creature + CreatureUtils.setCreatureTemplate(rVal, storedTemplate); + } + //rotator system + if(rawType.getRotatorSystem() != null){ + RotatorSystem system = rawType.getRotatorSystem(); + ServerRotatorTree rotatorTree = new ServerRotatorTree(rVal); + for(RotatorItem item : system.getRotatorItems()){ + //put actor rotator + ActorBoneRotator newRotator = new ActorBoneRotator(); + creatureActor.addBoneRotator(item.getBoneName(), newRotator); + //construct node for tree + RotatorHierarchyNode hierarchyNode = new RotatorHierarchyNode(); + hierarchyNode.setBone(item.getBoneName()); + for(RotatorConstraint constraint : item.getConstraints()){ + hierarchyNode.addRotatorConstraint(new electrosphere.entity.state.rotator.RotatorConstraint(constraint)); + } + rotatorTree.addRotatorNode(hierarchyNode); + } + rVal.putData(EntityDataStrings.SERVER_ROTATOR_TREE, rotatorTree); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, rotatorTree); + } + //add health system + rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem())); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.LIFE_STATE); + //idle tree & generic stuff all creatures have + rVal.putData(EntityDataStrings.IDLE_TREE, new IdleTree(rVal)); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.CREATURE); rVal.putData(EntityDataStrings.DATA_STRING_CREATURE_IS_CREATURE, true); rVal.putData(EntityDataStrings.DATA_STRING_CREATURE_TYPE, type); CreatureUtils.setFacingVector(rVal, new Vector3d(0,0,1)); @@ -485,25 +887,34 @@ public class CreatureUtils { e.putData(EntityDataStrings.DATA_STRING_MAX_NATURAL_VELOCITY, scalar); } - public static BehaviorTree getEntityMovementTree(Entity e){ - return (BehaviorTree)e.getData(EntityDataStrings.DATA_STRING_MOVEMENT_BT); + public static BehaviorTree clientGetEntityMovementTree(Entity e){ + return (BehaviorTree)e.getData(EntityDataStrings.CLIENT_MOVEMENT_BT); + } + + public static BehaviorTree serverGetEntityMovementTree(Entity e){ + return (BehaviorTree)e.getData(EntityDataStrings.SERVER_MOVEMENT_BT); } - public static void attachEntityMessageToMovementTree(Entity e, EntityMessage em){ - BehaviorTree movementTree = getEntityMovementTree(e); + public static void clientAttachEntityMessageToMovementTree(Entity e, EntityMessage em){ + BehaviorTree movementTree = clientGetEntityMovementTree(e); if(movementTree instanceof GroundMovementTree){ ((GroundMovementTree)movementTree).addNetworkMessage(em); } else if(movementTree instanceof AirplaneMovementTree){ ((AirplaneMovementTree)movementTree).addNetworkMessage(em); } } - - public static AttackTree getEntityAttackTree(Entity e){ - return (AttackTree)e.getData(EntityDataStrings.ATTACK_TREE); + + public static void serverAttachEntityMessageToMovementTree(Entity e, EntityMessage em){ + BehaviorTree movementTree = serverGetEntityMovementTree(e); + if(movementTree instanceof ServerGroundMovementTree){ + ((ServerGroundMovementTree)movementTree).addNetworkMessage(em); + } else if(movementTree instanceof AirplaneMovementTree){ + ((AirplaneMovementTree)movementTree).addNetworkMessage(em); + } } public static void attachEntityMessageToAttackTree(Entity e, EntityMessage em){ - getEntityAttackTree(e).addNetworkMessage(em); + clientGetAttackTree(e).addNetworkMessage(em); } public static String getType(Entity e){ @@ -526,16 +937,24 @@ public class CreatureUtils { return e.containsKey(EntityDataStrings.DATA_STRING_CREATURE_IS_CREATURE); } - public static AttackTree getAttackTree(Entity e){ - return (AttackTree)e.getData(EntityDataStrings.ATTACK_TREE); + public static AttackTree clientGetAttackTree(Entity e){ + return (AttackTree)e.getData(EntityDataStrings.CLIENT_ATTACK_TREE); + } + + public static ServerAttackTree serverGetAttackTree(Entity e){ + return (ServerAttackTree)e.getData(EntityDataStrings.SERVER_ATTACK_TREE); } public static IdleTree getIdleTree(Entity e){ return (IdleTree)e.getData(EntityDataStrings.IDLE_TREE); } - public static SprintTree getSprintTree(Entity e){ - return (SprintTree)e.getData(EntityDataStrings.SPRINT_TREE); + public static SprintTree clientGetSprintTree(Entity e){ + return (SprintTree)e.getData(EntityDataStrings.CLIENT_SPRINT_TREE); + } + + public static ServerSprintTree serverGetSprintTree(Entity e){ + return (ServerSprintTree)e.getData(EntityDataStrings.SERVER_SPRINT_TREE); } public static void setCreatureTemplate(Entity e, CreatureTemplate template){ diff --git a/src/main/java/electrosphere/entity/types/debug/DebugVisualizerUtils.java b/src/main/java/electrosphere/entity/types/debug/DebugVisualizerUtils.java index d973f1bb..596c44d1 100644 --- a/src/main/java/electrosphere/entity/types/debug/DebugVisualizerUtils.java +++ b/src/main/java/electrosphere/entity/types/debug/DebugVisualizerUtils.java @@ -4,13 +4,15 @@ import org.joml.Vector3d; import org.joml.Vector3f; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityUtils; public class DebugVisualizerUtils { - public static Entity spawnVectorVisualizer(Vector3d position, Vector3d direction){ - Entity rVal = EntityUtils.spawnDrawableEntity("Models/unitcube.fbx"); + public static Entity clientSpawnVectorVisualizer(Vector3d position, Vector3d direction){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, "Models/unitcube.fbx"); Vector3d pos = new Vector3d(position).add(new Vector3d(direction).normalize().mul(0.3)); EntityUtils.getPosition(rVal).set(pos); EntityUtils.getScale(rVal).set(0.05f,0.3f,0.05f); @@ -18,8 +20,9 @@ public class DebugVisualizerUtils { return rVal; } - public static Entity spawnUpdatingVectorVisualizer(Vector3d position, Vector3d direction){ - Entity rVal = EntityUtils.spawnDrawableEntity("Models/unitcube.fbx"); + public static Entity clientSpawnUpdatingVectorVisualizer(Vector3d position, Vector3d direction){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, "Models/unitcube.fbx"); Vector3d pos = new Vector3d(position).add(new Vector3d(direction).normalize().mul(0.3)); EntityUtils.getPosition(rVal).set(pos); EntityUtils.getScale(rVal).set(0.05f,0.3f,0.05f); diff --git a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java index 7fa3d6a3..1dd51f1d 100644 --- a/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java +++ b/src/main/java/electrosphere/entity/types/foliage/FoliageUtils.java @@ -3,9 +3,10 @@ package electrosphere.entity.types.foliage; import electrosphere.collision.dispatch.CollisionObject; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; -import electrosphere.entity.state.IdleTree; +import electrosphere.entity.state.idle.IdleTree; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.game.collision.PhysicsUtils; import electrosphere.game.collision.collidable.Collidable; @@ -28,7 +29,8 @@ public class FoliageUtils { public static Entity spawnBasicFoliage(String type){ FoliageType rawType = Globals.gameConfigCurrent.getFoliageMap().getFoliage(type); - Entity rVal = EntityUtils.spawnDrawableEntity(rawType.getModelPath()); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath()); // if(rawType.getPhysicsObjects() != null){ // List physicsObjects = rawType.getPhysicsObjects(); // for(PhysicsObject physicsTemplate : physicsObjects){ diff --git a/src/main/java/electrosphere/entity/types/hitbox/HitboxUtils.java b/src/main/java/electrosphere/entity/types/hitbox/HitboxUtils.java index e1866d16..b6312043 100644 --- a/src/main/java/electrosphere/entity/types/hitbox/HitboxUtils.java +++ b/src/main/java/electrosphere/entity/types/hitbox/HitboxUtils.java @@ -2,6 +2,7 @@ package electrosphere.entity.types.hitbox; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.attach.AttachUtils; @@ -12,6 +13,7 @@ import electrosphere.entity.state.life.LifeState; import electrosphere.entity.state.life.LifeUtils; import electrosphere.entity.state.movement.ProjectileTree; import electrosphere.game.server.effects.ParticleEffects; +import electrosphere.server.datacell.Realm; import java.util.List; @@ -27,9 +29,15 @@ import org.joml.Vector4f; */ public class HitboxUtils { - - public static Entity spawnRegularHitbox(Entity parent, String bone, float size){ - Entity rVal = new Entity(); + /** + * Spawns a hitbox entity on the client + * @param parent The parent entity to attach the hitbox to + * @param bone The bone on the parent to attach to + * @param size The radius of the hitsphere + * @return The hitbox entity + */ + public static Entity clientSpawnRegularHitbox(Entity parent, String bone, float size){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); HitboxData data = new HitboxData(); data.setActive(false); data.setBone(bone); @@ -39,12 +47,42 @@ public class HitboxUtils { rVal.putData(EntityDataStrings.HITBOX_DATA, data); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); - Globals.hitboxManager.registerHitbox(rVal); + Globals.clientHitboxManager.registerHitbox(rVal); return rVal; } - - public static Entity spawnRegularHurtbox(Entity parent, String bone, float size){ - Entity rVal = new Entity(); + + /** + * Spawns a hitbox entity on the server + * @param parent The parent entity to attach the hitbox to + * @param bone The bone to attach to the hitbox to + * @param size The radius of the hitsphere + * @return The hitbox entity + */ + public static Entity serverSpawnRegularHitbox(Entity parent, String bone, float size){ + Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0)); + HitboxData data = new HitboxData(); + data.setActive(false); + data.setBone(bone); + data.setRadius(size); + data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT); + rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent); + rVal.putData(EntityDataStrings.HITBOX_DATA, data); + rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); + rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); + Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal); + return rVal; + } + + + /** + * Spawns a hurtbox on the client + * @param parent The parent entity of the hurtbox + * @param bone The bone on the parent to attach the hurtbox to + * @param size The radius of the hurtsphere + * @return The hurtbox entity + */ + public static Entity clientSpawnRegularHurtbox(Entity parent, String bone, float size){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); HitboxData data = new HitboxData(); data.setActive(true); data.setBone(bone); @@ -54,7 +92,29 @@ public class HitboxUtils { rVal.putData(EntityDataStrings.HITBOX_DATA, data); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); - Globals.hitboxManager.registerHitbox(rVal); + Globals.clientHitboxManager.registerHitbox(rVal); + return rVal; + } + + /** + * Spawns a hurtbox on the server + * @param parent The parent entity of the hurtbox + * @param bone The bone on the parent to attach the hurtbox to + * @param size The radius of the hurtsphere + * @return The hurtbox entity + */ + public static Entity serverSpawnRegularHurtbox(Entity parent, String bone, float size){ + Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0)); + HitboxData data = new HitboxData(); + data.setActive(true); + data.setBone(bone); + data.setRadius(size); + data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT); + rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent); + rVal.putData(EntityDataStrings.HITBOX_DATA, data); + rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); + rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); + Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal); return rVal; } @@ -67,8 +127,8 @@ public class HitboxUtils { * @param filter an optional list of parent entities to not colide with * @return The hitbox entity */ - public static Entity spawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List filter){ - Entity rVal = new Entity(); + public static Entity clientSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List filter){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); HitboxData data = new HitboxData(); data.setActive(true); data.setPositionCallback(positionCallback); @@ -83,11 +143,41 @@ public class HitboxUtils { rVal.putData(EntityDataStrings.HITBOX_DATA, data); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); - Globals.hitboxManager.registerHitbox(rVal); + Globals.clientHitboxManager.registerHitbox(rVal); + return rVal; + } + + + /** + * More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone + * @param parent The parent entity of the hitbox + * @param positionCallback The position callback for keeping hitbox entity position up to date + * @param size The size of the hitbox + * @param hurtbox If true, it will instead be a hurtbox + * @param filter an optional list of parent entities to not colide with + * @return The hitbox entity + */ + public static Entity serverSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List filter){ + Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0)); + HitboxData data = new HitboxData(); + data.setActive(true); + data.setPositionCallback(positionCallback); + data.setRadius(size); + data.setEntityFilter(filter); + if(hurtbox){ + data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT); + } else { + data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT); + } + rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent); + rVal.putData(EntityDataStrings.HITBOX_DATA, data); + rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0)); + rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true); + Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal); return rVal; } - public static void updatePosition(Entity hitbox){ + public static void clientUpdatePosition(Entity hitbox){ Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT)); HitboxData hitboxData = getHitboxData(hitbox); String boneName = hitboxData.getBone(); @@ -105,6 +195,33 @@ public class HitboxUtils { worldPosition = worldPosition.rotate(rotation); + worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z)); + + EntityUtils.getPosition(hitbox).set(worldPosition); + } else { + HitboxPositionCallback positionCallback = hitboxData.getPositionCallback(); + EntityUtils.getPosition(hitbox).set(positionCallback.getPosition()); + } + } + + public static void serverUpdatePosition(Entity hitbox){ + Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT)); + HitboxData hitboxData = getHitboxData(hitbox); + String boneName = hitboxData.getBone(); + if(boneName != null){ + Quaternionf parentRotation = EntityUtils.getRotation(parent); + Vector3f positionScale = EntityUtils.getScale(parent); + Vector3f worldPosition = new Vector3f(); + Vector3f bonePosition = EntityUtils.getPoseActor(parent).getBonePosition(boneName); + Vector3d parentPos = EntityUtils.getPosition(parent); + worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z); + Quaternionf rotation = new Quaternionf(parentRotation); + + worldPosition = worldPosition.mul(positionScale); + + worldPosition = worldPosition.rotate(rotation); + + worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z)); EntityUtils.getPosition(hitbox).set(worldPosition); @@ -114,13 +231,13 @@ public class HitboxUtils { } } - public static void collideEntities(Entity generatorHitbox){ + public static void clientCollideEntities(Entity generatorHitbox){ // long generatorId = (Long)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_ID); //This is the entity the hitbox is attached to Entity generatorParent = (Entity)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT); - for(Entity receiverHitbox : Globals.hitboxManager.getAllHitboxes()){ + for(Entity receiverHitbox : Globals.clientHitboxManager.getAllHitboxes()){ Entity receiverParent = (Entity)receiverHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT); @@ -143,7 +260,7 @@ public class HitboxUtils { //and both hitboxes are active if( receiverParent != generatorParent && - Globals.collisionEngine.collisionSphereCheck(generatorHitbox, generatorData, receiverHitbox, receiverData) && + Globals.clientSceneWrapper.getCollisionEngine().collisionSphereCheck(generatorHitbox, generatorData, receiverHitbox, receiverData) && generatorData.isActive() && receiverData.isActive()){ //if two spheres collide, grab their hitbox types (eg hurt, hit, fire, etc) @@ -151,17 +268,67 @@ public class HitboxUtils { String receiverType = receiverData.getType(); if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){ - damageHitboxColision(generatorHitbox, receiverHitbox); + clientDamageHitboxColision(generatorHitbox, receiverHitbox); } if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){ - damageHitboxColision(receiverHitbox, generatorHitbox); + clientDamageHitboxColision(receiverHitbox, generatorHitbox); + } + } + } + } + + public static void serverCollideEntities(Entity generatorHitbox){ + // long generatorId = (Long)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_ID); + + //This is the entity the hitbox is attached to + Entity generatorParent = (Entity)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT); + + Realm generatorRealm = Globals.realmManager.getEntityRealm(generatorParent); + HitboxManager realmHitboxManager = generatorRealm.getHitboxManager(); + + for(Entity receiverHitbox : realmHitboxManager.getAllHitboxes()){ + + Entity receiverParent = (Entity)receiverHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT); + + HitboxData generatorData = getHitboxData(generatorHitbox); + HitboxData receiverData = getHitboxData(receiverHitbox); + + //check projectile filters + List generatorFilter = generatorData.getEntityFilter(); + if(generatorFilter != null && generatorFilter.contains(receiverParent)){ + continue; + } + + List receiverFilter = receiverData.getEntityFilter(); + if(receiverFilter != null && receiverFilter.contains(generatorParent)){ + continue; + } + + //if there is a collision + //and the collision isn't against itself + //and both hitboxes are active + if( + receiverParent != generatorParent && + generatorRealm.getCollisionEngine().collisionSphereCheck(generatorHitbox, generatorData, receiverHitbox, receiverData) && + generatorData.isActive() && + receiverData.isActive()){ + //if two spheres collide, grab their hitbox types (eg hurt, hit, fire, etc) + String generatorType = generatorData.getType(); + String receiverType = receiverData.getType(); + + if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){ + serverDamageHitboxColision(generatorHitbox, receiverHitbox); + } + + if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){ + serverDamageHitboxColision(receiverHitbox, generatorHitbox); } } } } - public static void damageHitboxColision(Entity hitbox, Entity hurtbox){ + public static void clientDamageHitboxColision(Entity hitbox, Entity hurtbox){ Entity hitboxParent = (Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT); Entity hurtboxParent = (Entity)hurtbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT); @@ -189,7 +356,51 @@ public class HitboxUtils { } else { int damage = 0; //for entities using attacktree - if(CreatureUtils.getAttackTree(hitboxParent) != null){ + if(CreatureUtils.clientGetAttackTree(hitboxParent) != null){ + damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage(); + } else { + //for entities using shooter tree + if(ProjectileTree.getProjectileTree(hitboxParent) != null){ + damage = (int)ProjectileTree.getProjectileTree(hitboxParent).getDamage(); + } + } + LifeUtils.getLifeState(hurtboxParent).damage(damage); + if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){ + EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint); + LifeUtils.getLifeState(hurtboxParent).revive(); + } + } + } + + public static void serverDamageHitboxColision(Entity hitbox, Entity hurtbox){ + + Entity hitboxParent = (Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT); + Entity hurtboxParent = (Entity)hurtbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT); + + //if the entity is attached to is an item, we need to compare with the parent of the item + //to make sure you don't stab yourself for instance + boolean isItem = ItemUtils.isItem(hitboxParent);//hitboxParent.containsKey(EntityDataStrings.ITEM_IS_ITEM); + Entity hitboxAttachParent = AttachUtils.getParent(hitboxParent); + + if(isItem){ + if(hitboxAttachParent != hurtboxParent){ + LifeState lifeState = LifeUtils.getLifeState(hurtboxParent); + int currentHp = lifeState.getLifeCurrent(); + int damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage(); + LifeUtils.getLifeState(hurtboxParent).damage(damage); + if(currentHp > lifeState.getLifeCurrent()){ + Vector3d hurtboxPos = EntityUtils.getPosition(hurtbox); + ParticleEffects.spawnBloodsplats(new Vector3f((float)hurtboxPos.x,(float)hurtboxPos.y,(float)hurtboxPos.z).add(0,0.1f,0), 20, 40); + } + if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){ + EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint); + LifeUtils.getLifeState(hurtboxParent).revive(); + } + } + } else { + int damage = 0; + //for entities using attacktree + if(CreatureUtils.serverGetAttackTree(hitboxParent) != null){ damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage(); } else { //for entities using shooter tree diff --git a/src/main/java/electrosphere/entity/types/item/ItemUtils.java b/src/main/java/electrosphere/entity/types/item/ItemUtils.java index 249d5c4b..95b19bc4 100644 --- a/src/main/java/electrosphere/entity/types/item/ItemUtils.java +++ b/src/main/java/electrosphere/entity/types/item/ItemUtils.java @@ -3,11 +3,14 @@ package electrosphere.entity.types.item; import electrosphere.collision.dispatch.CollisionObject; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; -import electrosphere.entity.state.collidable.CollidableTree; +import electrosphere.entity.state.collidable.ClientCollidableTree; +import electrosphere.entity.state.collidable.ServerCollidableTree; import electrosphere.entity.state.gravity.GravityTree; +import electrosphere.entity.state.gravity.ServerGravityTree; import electrosphere.entity.state.movement.GroundMovementTree; import electrosphere.entity.types.attach.AttachUtils; import electrosphere.entity.types.collision.CollisionObjUtils; @@ -26,6 +29,9 @@ import electrosphere.net.server.player.Player; import electrosphere.renderer.Model; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.ActorUtils; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; +import electrosphere.server.datacell.utils.ServerEntityTagUtils; import java.util.LinkedList; import java.util.List; @@ -43,17 +49,18 @@ public class ItemUtils { static final String genericItemIconPath = "Textures/icons/itemIconItemGeneric.png"; - public static Entity spawnBasicItem(String name){ + public static Entity clientSpawnBasicItem(String name){ Item item = Globals.gameConfigCurrent.getItemMap().getItem(name); - Entity rVal = EntityUtils.spawnDrawableEntity(item.getModelPath()); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, item.getModelPath()); if(item.getWeaponData() != null){ rVal.putData(EntityDataStrings.ITEM_IS_WEAPON, true); WeaponData weaponData = item.getWeaponData(); if(weaponData.getHitboxes() != null){ List hitboxList = new LinkedList(); for(HitboxData hitboxdata : weaponData.getHitboxes()){ - Entity hitbox = HitboxUtils.spawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); - Globals.hitboxManager.registerHitbox(hitbox); + Entity hitbox = HitboxUtils.clientSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); + Globals.clientHitboxManager.registerHitbox(hitbox); hitboxList.add(hitbox); } rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST,hitboxList); @@ -76,7 +83,7 @@ public class ItemUtils { rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - rVal.putData(EntityDataStrings.COLLIDABLE_TREE, new CollidableTree(rVal,collidable,rigidBody)); + rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, new ClientCollidableTree(rVal,collidable,rigidBody)); scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); @@ -88,10 +95,10 @@ public class ItemUtils { inertiaTensor.m22(mass * scale.x * scale.x / 2.0f); rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); - Globals.collisionEngine.registerPhysicsEntity(rVal); - Globals.collisionEngine.registerDynamicPhysicsEntity(rVal); - Globals.collisionEngine.registerCollisionObject(rigidBody, collidable); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.COLLIDABLE); + Globals.clientSceneWrapper.getCollisionEngine().registerPhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.COLLIDABLE); break; case "CUBE": rigidBody = PhysicsUtils.getCubeObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); @@ -100,7 +107,7 @@ public class ItemUtils { rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - rVal.putData(EntityDataStrings.COLLIDABLE_TREE, new CollidableTree(rVal,collidable,rigidBody)); + rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, new ClientCollidableTree(rVal,collidable,rigidBody)); scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); @@ -109,10 +116,10 @@ public class ItemUtils { inertiaTensor = new Matrix4f().identity().scale(mass * scale.x * scale.x / 6.0f).m33(1); rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); - Globals.collisionEngine.registerPhysicsEntity(rVal); - Globals.collisionEngine.registerDynamicPhysicsEntity(rVal); - Globals.collisionEngine.registerCollisionObject(rigidBody, collidable); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.COLLIDABLE); + Globals.clientSceneWrapper.getCollisionEngine().registerPhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.COLLIDABLE); break; } } @@ -127,11 +134,11 @@ public class ItemUtils { GravityTree gravityTree = new GravityTree(rVal,collidable,collisionObject,30); // gravityTree.setCollisionObject(collisionObject, collidable); rVal.putData(EntityDataStrings.GRAVITY_ENTITY, true); - rVal.putData(EntityDataStrings.GRAVITY_TREE, gravityTree); - Globals.entityManager.registerBehaviorTree(gravityTree); + rVal.putData(EntityDataStrings.CLIENT_GRAVITY_TREE, gravityTree); + Globals.clientSceneWrapper.getScene().registerBehaviorTree(gravityTree); break; case "TARGETABLE": - Globals.entityManager.registerEntityToTag(rVal, EntityTags.TARGETABLE); + Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.TARGETABLE); break; case "OUTLINE": rVal.putData(EntityDataStrings.DRAW_OUTLINE, true); @@ -158,7 +165,129 @@ public class ItemUtils { rVal.putData(EntityDataStrings.ITEM_TYPE, name); // rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(0.005f,0.005f,0.005f)); // rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaternionf().identity().rotateY((float)(-Math.PI/2)).rotateZ(-(float)(Math.PI/2))); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.ITEM); + Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.ITEM); + return rVal; + } + + + + public static Entity serverSpawnBasicItem(Realm realm, Vector3d position, String name){ + Item item = Globals.gameConfigCurrent.getItemMap().getItem(name); + Entity rVal = EntityCreationUtils.createServerEntity(realm, position);// EntityUtils.spawnDrawableEntity(item.getModelPath()); + EntityCreationUtils.makeEntityPoseable(rVal, item.getModelPath()); + if(item.getWeaponData() != null){ + rVal.putData(EntityDataStrings.ITEM_IS_WEAPON, true); + WeaponData weaponData = item.getWeaponData(); + if(weaponData.getHitboxes() != null){ + List hitboxList = new LinkedList(); + for(HitboxData hitboxdata : weaponData.getHitboxes()){ + Entity hitbox = HitboxUtils.serverSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius()); + realm.getHitboxManager().registerHitbox(hitbox); + hitboxList.add(hitbox); + } + rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST,hitboxList); + } + rVal.putData(EntityDataStrings.ITEM_WEAPON_CLASS,weaponData.getWeaponClass()); + rVal.putData(EntityDataStrings.ITEM_WEAPON_DATA_RAW,weaponData); + } + if(item.getCollidable() != null){ + CollidableTemplate physicsTemplate = item.getCollidable(); + CollisionObject rigidBody; + Collidable collidable; + float mass = 1.0f; + Matrix4f inertiaTensor; + Vector3f scale; + switch(physicsTemplate.getType()){ + case "CYLINDER": + rigidBody = PhysicsUtils.getCylinderObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); + collidable = new Collidable(rVal, Collidable.TYPE_ITEM); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); + rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); + rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); + rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, new ServerCollidableTree(rVal,collidable,rigidBody)); + + scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://scienceworld.wolfram.com/physics/MomentofInertiaCylinder.html + inertiaTensor = new Matrix4f(); + inertiaTensor.m00(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m11(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m22(mass * scale.x * scale.x / 2.0f); + rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + + realm.getCollisionEngine().registerPhysicsEntity(rVal); + realm.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE); + break; + case "CUBE": + rigidBody = PhysicsUtils.getCubeObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); + collidable = new Collidable(rVal, Collidable.TYPE_ITEM); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); + rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); + rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); + rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, new ServerCollidableTree(rVal,collidable,rigidBody)); + + scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://hepweb.ucsd.edu/ph110b/110b_notes/node26.html + inertiaTensor = new Matrix4f().identity().scale(mass * scale.x * scale.x / 6.0f).m33(1); + rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + + realm.getCollisionEngine().registerPhysicsEntity(rVal); + realm.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE); + break; + } + } + for(String token : item.getTokens()){ + switch(token){ + case "BLENDER_TRANSFORM": + ActorUtils.applyBlenderTransformer(rVal); + break; + case "GRAVITY": + Collidable collidable = (Collidable)rVal.getData(EntityDataStrings.PHYSICS_COLLIDABLE); + CollisionObject collisionObject = (CollisionObject)rVal.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); + ServerGravityTree gravityTree = new ServerGravityTree(rVal,collidable,collisionObject,30); +// gravityTree.setCollisionObject(collisionObject, collidable); + rVal.putData(EntityDataStrings.GRAVITY_ENTITY, true); + rVal.putData(EntityDataStrings.SERVER_GRAVITY_TREE, gravityTree); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, gravityTree); + break; + case "TARGETABLE": + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.TARGETABLE); + break; + case "OUTLINE": + rVal.putData(EntityDataStrings.DRAW_OUTLINE, true); + break; + } + } + if(item.getEquipWhitelist() != null){ + rVal.putData(EntityDataStrings.ITEM_EQUIP_WHITELIST, item.getEquipWhitelist()); + } + if(item.getIdleAnim() != null){ + rVal.putData(EntityDataStrings.ANIM_IDLE,item.getIdleAnim()); + } + if(item.getIconPath() != null && !item.getIconPath().equals("")){ + rVal.putData(EntityDataStrings.ITEM_ICON,item.getIconPath()); + } else { + rVal.putData(EntityDataStrings.ITEM_ICON,genericItemIconPath); + } + if(item.getEquipClass() != null){ + rVal.putData(EntityDataStrings.ITEM_EQUIP_CLASS,item.getEquipClass()); + } + rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); + rVal.putData(EntityDataStrings.ITEM_IS_ITEM, true); + rVal.putData(EntityDataStrings.ITEM_IS_IN_INVENTORY, false); + rVal.putData(EntityDataStrings.ITEM_TYPE, name); +// rVal.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(0.005f,0.005f,0.005f)); +// rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaternionf().identity().rotateY((float)(-Math.PI/2)).rotateZ(-(float)(Math.PI/2))); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.ITEM); return rVal; } @@ -182,8 +311,11 @@ public class ItemUtils { if(item.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){ item.removeData(EntityDataStrings.PHYSICS_COLLIDABLE); } - if(item.containsKey(EntityDataStrings.COLLIDABLE_TREE)){ - item.removeData(EntityDataStrings.COLLIDABLE_TREE); + if(item.containsKey(EntityDataStrings.SERVER_COLLIDABLE_TREE)){ + item.removeData(EntityDataStrings.SERVER_COLLIDABLE_TREE); + } + if(item.containsKey(EntityDataStrings.CLIENT_COLLIDABLE_TREE)){ + item.removeData(EntityDataStrings.CLIENT_COLLIDABLE_TREE); } } @@ -267,9 +399,9 @@ public class ItemUtils { * @param item The item to recreate * @param containingParent The parent that contains the item */ - public static Entity recreateContainerItem(Entity item, Entity containingParent){ + public static Entity clientRecreateContainerItem(Entity item, Entity containingParent){ if(isItem(item)){ - Entity rVal = new Entity(); + Entity rVal = EntityCreationUtils.createClientNonSpatialEntity(); if(getEquipWhitelist(item) != null){ rVal.putData(EntityDataStrings.ITEM_EQUIP_WHITELIST, getEquipWhitelist(item)); } @@ -279,30 +411,76 @@ public class ItemUtils { rVal.putData(EntityDataStrings.ITEM_IS_IN_INVENTORY, true); ItemUtils.setContainingParent(rVal, containingParent); rVal.putData(EntityDataStrings.ITEM_TYPE, item.getData(EntityDataStrings.ITEM_TYPE)); - Globals.entityManager.registerEntity(rVal); + Globals.clientSceneWrapper.getScene().registerEntity(rVal); return rVal; } else { return null; } } - public static void destroyInWorldItem(Entity item){ + + /** + * Emits an entity which represents the item inside a container + * @param item The item to recreate + * @param containingParent The parent that contains the item + */ + public static Entity serverRecreateContainerItem(Entity item, Entity containingParent){ + if(isItem(item)){ + Entity rVal = EntityCreationUtils.createRealmlessServerEntity(); + if(getEquipWhitelist(item) != null){ + rVal.putData(EntityDataStrings.ITEM_EQUIP_WHITELIST, getEquipWhitelist(item)); + } + rVal.putData(EntityDataStrings.ITEM_ICON,ItemUtils.getItemIcon(item)); + rVal.putData(EntityDataStrings.ITEM_EQUIP_CLASS, item.getData(EntityDataStrings.ITEM_EQUIP_CLASS)); + rVal.putData(EntityDataStrings.ITEM_IS_ITEM, true); + rVal.putData(EntityDataStrings.ITEM_IS_IN_INVENTORY, true); + ItemUtils.setContainingParent(rVal, containingParent); + rVal.putData(EntityDataStrings.ITEM_TYPE, item.getData(EntityDataStrings.ITEM_TYPE)); + return rVal; + } else { + return null; + } + } + + public static void clientDestroyInWorldItem(Entity item){ if(isItem(item)){ //destroy physics if(item.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY) && item.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){ //destroy physics //this deregisters from all four & unhooks rigid bodies from the physics runtime - Globals.collisionEngine.destroyEntityThatHasPhysics(item); + Globals.clientSceneWrapper.getCollisionEngine().destroyEntityThatHasPhysics(item); //destroy hitboxes List hitboxes = HitboxUtils.getHitboxAssociatedList(item); if(hitboxes != null){ for(Entity hitbox : hitboxes){ - Globals.hitboxManager.deregisterHitbox(hitbox); + Globals.clientHitboxManager.deregisterHitbox(hitbox); HitboxUtils.getHitboxData(hitbox).setActive(false); } } //destroy graphics - EntityUtils.cleanUpDrawableEntity(item); + EntityUtils.cleanUpEntity(item); + } + } + } + + public static void serverDestroyInWorldItem(Entity item){ + if(isItem(item)){ + //destroy physics + if(item.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY) && item.containsKey(EntityDataStrings.PHYSICS_COLLIDABLE)){ + Realm itemRealm = Globals.realmManager.getEntityRealm(item); + //destroy physics + //this deregisters from all four & unhooks rigid bodies from the physics runtime + itemRealm.getCollisionEngine().destroyEntityThatHasPhysics(item); + //destroy hitboxes + List hitboxes = HitboxUtils.getHitboxAssociatedList(item); + if(hitboxes != null){ + for(Entity hitbox : hitboxes){ + itemRealm.getHitboxManager().deregisterHitbox(hitbox); + HitboxUtils.getHitboxData(hitbox).setActive(false); + } + } + //destroy graphics + EntityUtils.cleanUpEntity(item); } } } @@ -312,7 +490,7 @@ public class ItemUtils { } public static void destroyInInventoryItem(Entity item){ - Globals.entityManager.deregisterEntity(item); + EntityUtils.cleanUpEntity(item); } public static String getItemIcon(Entity item){ diff --git a/src/main/java/electrosphere/entity/types/object/ObjectUtils.java b/src/main/java/electrosphere/entity/types/object/ObjectUtils.java index c4cbe6d8..3325178e 100644 --- a/src/main/java/electrosphere/entity/types/object/ObjectUtils.java +++ b/src/main/java/electrosphere/entity/types/object/ObjectUtils.java @@ -1,20 +1,25 @@ package electrosphere.entity.types.object; import org.joml.Matrix4f; +import org.joml.Vector3d; import org.joml.Vector3f; import electrosphere.collision.dispatch.CollisionObject; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.BehaviorTree; -import electrosphere.entity.state.IdleTree; -import electrosphere.entity.state.collidable.CollidableTree; +import electrosphere.entity.state.collidable.ClientCollidableTree; +import electrosphere.entity.state.collidable.ServerCollidableTree; import electrosphere.entity.state.gravity.GravityTree; +import electrosphere.entity.state.gravity.ServerGravityTree; +import electrosphere.entity.state.idle.IdleTree; import electrosphere.entity.state.inventory.InventoryState; import electrosphere.entity.state.inventory.InventoryUtils; +import electrosphere.entity.state.inventory.ServerInventoryState; import electrosphere.entity.state.inventory.UnrelationalInventoryState; import electrosphere.entity.state.life.LifeState; import electrosphere.entity.types.collision.CollisionObjUtils; @@ -24,12 +29,19 @@ import electrosphere.game.data.creature.type.CollidableTemplate; import electrosphere.game.data.object.type.ObjectData; import electrosphere.renderer.actor.Actor; import electrosphere.renderer.actor.ActorUtils; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.datacell.utils.EntityLookupUtils; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; +import electrosphere.server.datacell.utils.ServerEntityTagUtils; +import electrosphere.server.poseactor.PoseActor; public class ObjectUtils { - public static Entity spawnBasicObject(String type){ + public static Entity clientSpawnBasicObject(String type){ ObjectData rawType = Globals.gameConfigCurrent.getObjectTypeLoader().getObject(type); - Entity rVal = EntityUtils.spawnDrawableEntity(rawType.getModelPath()); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath()); Actor creatureActor = EntityUtils.getActor(rVal); //forward-searching tokens boolean collisionMakeDynamic = true; @@ -40,21 +52,21 @@ public class ObjectUtils { } break; case "GENERATE_COLLISION_OBJECT": { Globals.assetManager.addCollisionMeshToQueue(rawType.getModelPath()); - Globals.entityManager.registerBehaviorTree(new BehaviorTree() {public void simulate(float deltaTime) { + Globals.clientSceneWrapper.getScene().registerBehaviorTree(new BehaviorTree() {public void simulate(float deltaTime) { CollisionObject collisionObject = Globals.assetManager.fetchCollisionObject(rawType.getModelPath()); if(collisionObject != null){ - Globals.entityManager.deregisterBehaviorTree(this); - CollisionObjUtils.attachCollisionObjectToEntity(rVal, collisionObject, 0, Collidable.TYPE_OBJECT); + Globals.clientSceneWrapper.getScene().deregisterBehaviorTree(this); + CollisionObjUtils.clientAttachCollisionObjectToEntity(rVal, collisionObject, 0, Collidable.TYPE_OBJECT); } }}); } break; case "GENERATE_COLLISION_TERRAIN": { Globals.assetManager.addCollisionMeshToQueue(rawType.getModelPath()); - Globals.entityManager.registerBehaviorTree(new BehaviorTree() {public void simulate(float deltaTime) { + Globals.clientSceneWrapper.getScene().registerBehaviorTree(new BehaviorTree() {public void simulate(float deltaTime) { CollisionObject collisionObject = Globals.assetManager.fetchCollisionObject(rawType.getModelPath()); if(collisionObject != null){ - Globals.entityManager.deregisterBehaviorTree(this); - CollisionObjUtils.attachCollisionObjectToEntity(rVal, collisionObject, 0, Collidable.TYPE_TERRAIN); + Globals.clientSceneWrapper.getScene().deregisterBehaviorTree(this); + CollisionObjUtils.clientAttachCollisionObjectToEntity(rVal, collisionObject, 0, Collidable.TYPE_TERRAIN); } }}); } break; @@ -76,8 +88,8 @@ public class ObjectUtils { rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - CollidableTree tree = new CollidableTree(rVal,collidable,rigidBody, collisionMakeDynamic); - rVal.putData(EntityDataStrings.COLLIDABLE_TREE, tree); + ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody, collisionMakeDynamic); + rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree); scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); @@ -89,9 +101,9 @@ public class ObjectUtils { inertiaTensor.m22(mass * scale.x * scale.x / 2.0f); rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); - Globals.collisionEngine.registerPhysicsEntity(rVal); - Globals.entityManager.registerBehaviorTree(tree); - Globals.collisionEngine.registerCollisionObject(rigidBody, collidable); + Globals.clientSceneWrapper.getCollisionEngine().registerPhysicsEntity(rVal); + Globals.clientSceneWrapper.getScene().registerBehaviorTree(tree); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable); } break; case "CUBE": { rigidBody = PhysicsUtils.getCubeObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); @@ -100,8 +112,8 @@ public class ObjectUtils { rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - CollidableTree tree = new CollidableTree(rVal,collidable,rigidBody, collisionMakeDynamic); - rVal.putData(EntityDataStrings.COLLIDABLE_TREE, tree); + ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody, collisionMakeDynamic); + rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree); scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); @@ -110,13 +122,13 @@ public class ObjectUtils { inertiaTensor = new Matrix4f().identity().scale(mass * scale.x * scale.x / 6.0f).m33(1); rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); - Globals.collisionEngine.registerPhysicsEntity(rVal); - Globals.entityManager.registerBehaviorTree(tree); - Globals.collisionEngine.registerCollisionObject(rigidBody, collidable); + Globals.clientSceneWrapper.getCollisionEngine().registerPhysicsEntity(rVal); + Globals.clientSceneWrapper.getScene().registerBehaviorTree(tree); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable); } break; } - Globals.collisionEngine.registerDynamicPhysicsEntity(rVal); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.COLLIDABLE); + Globals.clientSceneWrapper.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.COLLIDABLE); } for(String token : rawType.getTokens()){ switch(token){ @@ -129,15 +141,163 @@ public class ObjectUtils { GravityTree gravityTree = new GravityTree(rVal,collidable,collisionObject,30); // gravityTree.setCollisionObject(collisionObject, collidable); rVal.putData(EntityDataStrings.GRAVITY_ENTITY, true); - rVal.putData(EntityDataStrings.GRAVITY_TREE, gravityTree); - Globals.entityManager.registerBehaviorTree(gravityTree); + rVal.putData(EntityDataStrings.CLIENT_GRAVITY_TREE, gravityTree); + Globals.clientSceneWrapper.getScene().registerBehaviorTree(gravityTree); break; case "TARGETABLE": - Globals.entityManager.registerEntityToTag(rVal, EntityTags.TARGETABLE); + Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.TARGETABLE); break; case "INVENTORY": rVal.putData(EntityDataStrings.NATURAL_INVENTORY,UnrelationalInventoryState.createUnrelationalInventory(10)); - InventoryUtils.setInventoryState(rVal, InventoryState.createInventoryState(rVal)); + InventoryUtils.clientSetInventoryState(rVal, InventoryState.clientCreateInventoryState(rVal)); + break; + case "OUTLINE": + rVal.putData(EntityDataStrings.DRAW_OUTLINE, true); + break; + case "TERRAIN_COLLISION": { + CollisionObjUtils.getCollidable(rVal).overrideType(Collidable.TYPE_TERRAIN); + } break; + } + } + //add health system + // rVal.putData(EntityDataStrings.LIFE_STATE, new LifeState(rVal, rawType.getHealthSystem())); + // Globals.entityManager.registerLifeStateEntity(rVal); + //idle tree & generic stuff all objects have + rVal.putData(EntityDataStrings.IDLE_TREE, new IdleTree(rVal)); + rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); + return rVal; + } + + + + /** + * Spawns a server-side object + * @param type The type of object to spawn + * @return The object + */ + public static Entity serverSpawnBasicObject(Realm realm, Vector3d position, String type){ + ObjectData rawType = Globals.gameConfigCurrent.getObjectTypeLoader().getObject(type); + Entity rVal = EntityCreationUtils.createServerEntity(realm, position); + EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath()); + //register to global entity id lookup table + EntityLookupUtils.registerServerEntity(rVal); + //register to data cell + ServerDataCell entityDataCell = realm.getDataCellManager().tryCreateCellAtPoint(position); + entityDataCell.getScene().registerEntity(rVal); + //maps this entity to its realm + Globals.realmManager.mapEntityToRealm(rVal, realm); + //enable behavior tree tracking + ServerBehaviorTreeUtils.registerEntity(rVal); + + + PoseActor creatureActor = EntityUtils.getPoseActor(rVal); + //forward-searching tokens + boolean collisionMakeDynamic = true; + for(String token : rawType.getTokens()){ + switch(token){ + case "DISABLE_COLLISION_REACTION": { + collisionMakeDynamic = false; + } break; + case "GENERATE_COLLISION_OBJECT": { + Globals.assetManager.addCollisionMeshToQueue(rawType.getModelPath()); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, new BehaviorTree() {public void simulate(float deltaTime) { + CollisionObject collisionObject = Globals.assetManager.fetchCollisionObject(rawType.getModelPath()); + if(collisionObject != null){ + ServerBehaviorTreeUtils.detatchBTreeFromEntity(rVal, this); + CollisionObjUtils.serverAttachCollisionObjectToEntity(rVal, collisionObject, 0, Collidable.TYPE_OBJECT); + } + }}); + } break; + case "GENERATE_COLLISION_TERRAIN": { + Globals.assetManager.addCollisionMeshToQueue(rawType.getModelPath()); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, new BehaviorTree() {public void simulate(float deltaTime) { + CollisionObject collisionObject = Globals.assetManager.fetchCollisionObject(rawType.getModelPath()); + if(collisionObject != null){ + ServerBehaviorTreeUtils.detatchBTreeFromEntity(rVal, this); + CollisionObjUtils.serverAttachCollisionObjectToEntity(rVal, collisionObject, 0, Collidable.TYPE_TERRAIN); + } + }}); + } break; + } + } + //main entity construction + if(rawType.getCollidable() != null){ + CollidableTemplate physicsTemplate = rawType.getCollidable(); + CollisionObject rigidBody; + Collidable collidable; + float mass = 1.0f; + Matrix4f inertiaTensor; + Vector3f scale; + switch(physicsTemplate.getType()){ + case "CYLINDER": { + rigidBody = PhysicsUtils.getCylinderObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); + collidable = new Collidable(rVal, Collidable.TYPE_OBJECT); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); + rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); + rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); + ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody, collisionMakeDynamic); + rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree); + + scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://scienceworld.wolfram.com/physics/MomentofInertiaCylinder.html + inertiaTensor = new Matrix4f(); + inertiaTensor.m00(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m11(mass * scale.y * scale.y / 12.0f + mass * scale.x * scale.x / 4.0f); + inertiaTensor.m22(mass * scale.x * scale.x / 2.0f); + rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + + realm.getCollisionEngine().registerPhysicsEntity(rVal); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, tree); + realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + } break; + case "CUBE": { + rigidBody = PhysicsUtils.getCubeObject(new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3())); + collidable = new Collidable(rVal, Collidable.TYPE_OBJECT); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, rigidBody); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_OFFSET, new Vector3f(physicsTemplate.getOffsetX(),physicsTemplate.getOffsetY(),physicsTemplate.getOffsetZ())); + rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); + rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); + ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody, collisionMakeDynamic); + rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree); + + scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + //inertia tensor + //https://hepweb.ucsd.edu/ph110b/110b_notes/node26.html + inertiaTensor = new Matrix4f().identity().scale(mass * scale.x * scale.x / 6.0f).m33(1); + rVal.putData(EntityDataStrings.PHYSICS_INVERSE_INERTIA_TENSOR, inertiaTensor.invert()); + + realm.getCollisionEngine().registerPhysicsEntity(rVal); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, tree); + realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + } break; + } + realm.getCollisionEngine().registerDynamicPhysicsEntity(rVal); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE); + } + for(String token : rawType.getTokens()){ + switch(token){ + case "BLENDER_TRANSFORM": + ActorUtils.applyBlenderTransformer(rVal); + break; + case "GRAVITY": + Collidable collidable = (Collidable)rVal.getData(EntityDataStrings.PHYSICS_COLLIDABLE); + CollisionObject collisionObject = (CollisionObject)rVal.getData(EntityDataStrings.PHYSICS_COLLISION_BODY); + ServerGravityTree gravityTree = new ServerGravityTree(rVal,collidable,collisionObject,30); +// gravityTree.setCollisionObject(collisionObject, collidable); + rVal.putData(EntityDataStrings.GRAVITY_ENTITY, true); + rVal.putData(EntityDataStrings.SERVER_GRAVITY_TREE, gravityTree); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, gravityTree); + break; + case "TARGETABLE": + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.TARGETABLE); + break; + case "INVENTORY": + rVal.putData(EntityDataStrings.NATURAL_INVENTORY,UnrelationalInventoryState.createUnrelationalInventory(10)); + InventoryUtils.serverSetInventoryState(rVal, ServerInventoryState.serverCreateInventoryState(rVal)); break; case "OUTLINE": rVal.putData(EntityDataStrings.DRAW_OUTLINE, true); diff --git a/src/main/java/electrosphere/entity/types/particle/ParticleUtils.java b/src/main/java/electrosphere/entity/types/particle/ParticleUtils.java index 9df59add..5e502ab3 100644 --- a/src/main/java/electrosphere/entity/types/particle/ParticleUtils.java +++ b/src/main/java/electrosphere/entity/types/particle/ParticleUtils.java @@ -2,6 +2,7 @@ package electrosphere.entity.types.particle; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; @@ -22,23 +23,25 @@ public class ParticleUtils { - public static Entity spawnBillboardProjectileParticle(String texture, int maxLife, Vector3f destination, float velocity, float acceleration){ - Entity rVal = EntityUtils.spawnDrawableEntity(Globals.particleBillboardModel); + public static Entity clientSpawnBillboardProjectileParticle(String texture, int maxLife, Vector3f destination, float velocity, float acceleration){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, Globals.particleBillboardModel); EntityUtils.getActor(rVal).setTextureOverride(texture); Globals.assetManager.addTexturePathtoQueue(texture); ParticleTree particleTree = new ParticleTree(rVal, maxLife, destination, velocity, acceleration, true); rVal.putData(EntityDataStrings.PARTICLE_TREE, particleTree); rVal.putData(EntityDataStrings.IS_PARTICLE, true); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.PARTICLE); + Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.PARTICLE); return rVal; } - public static Entity spawnStaticBillboardParticle(){ - Entity rVal = EntityUtils.spawnDrawableEntity(Globals.particleBillboardModel); + public static Entity clientSpawnStaticBillboardParticle(){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, Globals.particleBillboardModel); ParticleTree particleTree = new ParticleTree(rVal, 10, new Vector3f(0,0,0), 0, 0, false); rVal.putData(EntityDataStrings.PARTICLE_TREE, particleTree); rVal.putData(EntityDataStrings.IS_PARTICLE, true); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.PARTICLE); + Globals.clientSceneWrapper.getScene().registerEntityToTag(rVal, EntityTags.PARTICLE); return rVal; } diff --git a/src/main/java/electrosphere/entity/types/projectile/ProjectileUtils.java b/src/main/java/electrosphere/entity/types/projectile/ProjectileUtils.java index 48d21cbd..693a650d 100644 --- a/src/main/java/electrosphere/entity/types/projectile/ProjectileUtils.java +++ b/src/main/java/electrosphere/entity/types/projectile/ProjectileUtils.java @@ -11,16 +11,50 @@ import org.joml.Vector3f; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.movement.ProjectileTree; import electrosphere.entity.types.hitbox.HitboxUtils; import electrosphere.entity.types.hitbox.HitboxUtils.HitboxPositionCallback; import electrosphere.game.data.projectile.ProjectileType; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; public class ProjectileUtils { - public static Entity spawnBasicProjectile(String model, Vector3d initialPosition, Quaternionf rotation, int maxLife, Vector3f initialVector, float velocity){ - Entity rVal = EntityUtils.spawnDrawableEntity(model); + /** + * Spawns a basic projectile entity on the client + * @param model The model + * @param initialPosition The initial position + * @param rotation The rotation + * @param maxLife The maximum life + * @param initialVector The initial vector + * @param velocity The velocity + * @return The projectile entity + */ + public static Entity clientSpawnBasicProjectile(String model, Vector3d initialPosition, Quaternionf rotation, int maxLife, Vector3f initialVector, float velocity){ + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, model); + Globals.assetManager.addModelPathToQueue(model); + ProjectileTree tree = new ProjectileTree(rVal,maxLife,new Vector3d(initialVector),velocity); + EntityUtils.getPosition(rVal).set(initialPosition); + EntityUtils.getRotation(rVal).rotationTo(new Vector3f(0,0,1), new Vector3f((float)initialVector.x,(float)initialVector.y,(float)initialVector.z)).normalize(); + Globals.clientSceneWrapper.getScene().registerBehaviorTree(tree); + return rVal; + } + + /** + * Spawns a basic projectile entity on the server + * @param model The model + * @param initialPosition The initial position + * @param rotation The rotation + * @param maxLife The maximum life + * @param initialVector The initial vector + * @param velocity The velocity + * @return The projectile entity + */ + public static Entity serverSpawnBasicProjectile(Realm realm, String model, Vector3d initialPosition, Quaternionf rotation, int maxLife, Vector3f initialVector, float velocity){ + Entity rVal = EntityCreationUtils.createServerEntity(realm, initialPosition); Globals.assetManager.addModelPathToQueue(model); ProjectileTree tree = new ProjectileTree(rVal,maxLife,new Vector3d(initialVector),velocity); EntityUtils.getPosition(rVal).set(initialPosition); @@ -29,7 +63,7 @@ public class ProjectileUtils { // ParticleTree particleTree = new ParticleTree(rVal, maxLife, destination, velocity, acceleration, true); // rVal.putData(EntityDataStrings.PARTICLE_TREE, particleTree); // rVal.putData(EntityDataStrings.IS_PARTICLE, true); - Globals.entityManager.registerBehaviorTree(tree); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, tree); return rVal; } @@ -42,21 +76,53 @@ public class ProjectileUtils { * @param parent The parent that fired said projectile * @return The projectile entity */ - public static Entity spawnProjectile(String projectileType, Vector3d initialPosition, Vector3d initialVector, Entity parent){ + public static Entity clientSpawnProjectile(String projectileType, Vector3d initialPosition, Vector3d initialVector, Entity parent){ ProjectileType rawType = Globals.gameConfigCurrent.getProjectileMap().getType(projectileType); - Entity rVal = EntityUtils.spawnDrawableEntity(rawType.getModelPath()); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath()); //initial coordinates EntityUtils.getRotation(rVal).rotationTo(new Vector3f(0,0,1), new Vector3f((float)initialVector.x,(float)initialVector.y,(float)initialVector.z)).normalize(); EntityUtils.getPosition(rVal).set(initialPosition); //projectile behavior tree ProjectileTree tree = new ProjectileTree(rVal,rawType.getMaxLife(),initialVector,rawType.getVelocity(), rawType.getDamage()); - Globals.entityManager.registerBehaviorTree(tree); + Globals.clientSceneWrapper.getScene().registerBehaviorTree(tree); ProjectileTree.setProjectileTree(rVal, tree); //filter construction List filter = new LinkedList(); filter.add(parent); //collidable - HitboxUtils.spawnRegularHitbox(rVal, new HitboxPositionCallback() { + HitboxUtils.clientSpawnRegularHitbox(rVal, new HitboxPositionCallback() { + public Vector3d getPosition(){ + return EntityUtils.getPosition(rVal); + } + }, rawType.getHitboxRadius(), false, filter); + return rVal; + } + + /** + * More sophisticated function for spawning projectiles. Uses the projectiles.json file to store data about types to spawn. + * Also filters the parent from being hit by their own projectiles. + * @param projectileType The type in projectiles.json to spawn + * @param initialPosition The initial position of the projectile + * @param initialVector The initial velocity of the projectile + * @param parent The parent that fired said projectile + * @return The projectile entity + */ + public static Entity serverSpawnProjectile(Realm realm, String projectileType, Vector3d initialPosition, Vector3d initialVector, Entity parent){ + ProjectileType rawType = Globals.gameConfigCurrent.getProjectileMap().getType(projectileType); + Entity rVal = EntityCreationUtils.createServerEntity(realm, initialPosition); + //initial coordinates + EntityUtils.getRotation(rVal).rotationTo(new Vector3f(0,0,1), new Vector3f((float)initialVector.x,(float)initialVector.y,(float)initialVector.z)).normalize(); + EntityUtils.getPosition(rVal).set(initialPosition); + //projectile behavior tree + ProjectileTree tree = new ProjectileTree(rVal,rawType.getMaxLife(),initialVector,rawType.getVelocity(), rawType.getDamage()); + ServerBehaviorTreeUtils.attachBTreeToEntity(rVal, tree); + ProjectileTree.setProjectileTree(rVal, tree); + //filter construction + List filter = new LinkedList(); + filter.add(parent); + //collidable + HitboxUtils.serverSpawnRegularHitbox(rVal, new HitboxPositionCallback() { public Vector3d getPosition(){ return EntityUtils.getPosition(rVal); } diff --git a/src/main/java/electrosphere/entity/types/structure/StructureUtils.java b/src/main/java/electrosphere/entity/types/structure/StructureUtils.java index d83eb496..d31ed830 100644 --- a/src/main/java/electrosphere/entity/types/structure/StructureUtils.java +++ b/src/main/java/electrosphere/entity/types/structure/StructureUtils.java @@ -2,6 +2,7 @@ package electrosphere.entity.types.structure; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.collision.CollisionObjUtils; @@ -11,6 +12,7 @@ import electrosphere.game.data.structure.type.model.StructureType; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.server.player.Player; +import electrosphere.server.datacell.Realm; import org.joml.Matrix4f; import org.joml.Quaternionf; @@ -25,9 +27,10 @@ import org.joml.Vector4f; public class StructureUtils { - public static Entity spawnBasicStructure(String type, Vector3f position, Quaternionf rotation){ + public static Entity clientSpawnBasicStructure(String type, Vector3f position, Quaternionf rotation){ StructureType rawType = Globals.gameConfigCurrent.getStructureTypeMap().getType(type); - Entity rVal = EntityUtils.spawnDrawableEntity(rawType.getModelPath()); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, rawType.getModelPath()); EntityUtils.getPosition(rVal).set(position); EntityUtils.getRotation(rVal).set(rotation); for(CollisionObjectTemplate template : rawType.getCollision()){ @@ -37,7 +40,34 @@ public class StructureUtils { Vector4f rotatedPosition = rotationTransform.transform(new Vector4f(template.getPositionX(),template.getPositionY(),template.getPositionZ(),1.0f)); Vector3f cubePosition = new Vector3f(position).add(rotatedPosition.x,rotatedPosition.y,rotatedPosition.z); Quaternionf cubeRotation = new Quaternionf(rotation).mul(new Quaternionf(template.getRotationX(),template.getRotationY(),template.getRotationZ(),template.getRotationW())).normalize(); - CollisionObjUtils.attachCollisionCube(new Vector3f(template.getScaleX(),template.getScaleY(),template.getScaleZ()), cubePosition, cubeRotation, rVal); + CollisionObjUtils.clientAttachCollisionCube(new Vector3f(template.getScaleX(),template.getScaleY(),template.getScaleZ()), cubePosition, cubeRotation, rVal); +// Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); +// Globals.collisionEngine.registerPhysicsEntity(rVal); +// Globals.collisionEngine.registerCollisionObject(rigidBody, collidable); + break; + case CollisionObjectTemplate.TYPE_PLANE: + throw new UnsupportedOperationException("Haven't implemented plane collision on structures"); + } + } + rVal.putData(EntityDataStrings.STRUCTURE_IS_STRUCTURE,true); + rVal.putData(EntityDataStrings.STRUCTURE_TYPE,type); + return rVal; + } + + public static Entity serverSpawnBasicStructure(String type, Realm realm, Vector3d position, Quaternionf rotation){ + StructureType rawType = Globals.gameConfigCurrent.getStructureTypeMap().getType(type); + Entity rVal = EntityCreationUtils.createServerEntity(realm, position); + EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath()); + EntityUtils.getPosition(rVal).set(position); + EntityUtils.getRotation(rVal).set(rotation); + for(CollisionObjectTemplate template : rawType.getCollision()){ + switch(template.getType()){ + case CollisionObjectTemplate.TYPE_CUBE: + Matrix4f rotationTransform = new Matrix4f().rotate(rotation); + Vector4f rotatedPosition = rotationTransform.transform(new Vector4f(template.getPositionX(),template.getPositionY(),template.getPositionZ(),1.0f)); + Vector3f cubePosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).add(rotatedPosition.x,rotatedPosition.y,rotatedPosition.z); + Quaternionf cubeRotation = new Quaternionf(rotation).mul(new Quaternionf(template.getRotationX(),template.getRotationY(),template.getRotationZ(),template.getRotationW())).normalize(); + CollisionObjUtils.serverAttachCollisionCube(new Vector3f(template.getScaleX(),template.getScaleY(),template.getScaleZ()), cubePosition, cubeRotation, rVal); // Collidable collidable = new Collidable(rVal, Collidable.TYPE_STRUCTURE); // Globals.collisionEngine.registerPhysicsEntity(rVal); // Globals.collisionEngine.registerCollisionObject(rigidBody, collidable); diff --git a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java index 24cecd13..328d289d 100644 --- a/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java +++ b/src/main/java/electrosphere/entity/types/terrain/TerrainChunk.java @@ -5,8 +5,10 @@ import org.joml.Vector3f; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; +import electrosphere.entity.ServerEntityUtils; import electrosphere.game.client.terrain.manager.ClientTerrainManager; import electrosphere.game.collision.PhysicsUtils; import electrosphere.renderer.Model; @@ -156,12 +158,14 @@ public class TerrainChunk { TerrainChunkData data = TerrainChunkModelGeneration.generateTerrainChunkData(terrainGrid, textureGrid); String modelPath = ClientTerrainManager.queueTerrainGridGeneration(data); - Entity rVal = EntityUtils.spawnDrawableEntityWithPreexistingModel(modelPath); - PhysicsUtils.attachTerrainChunkRigidBody(rVal, data); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(rVal, modelPath); + // Entity rVal = EntityUtils.spawnDrawableEntityWithPreexistingModel(modelPath); + PhysicsUtils.clientAttachTerrainChunkRigidBody(rVal, data); rVal.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); - EntityUtils.repositionEntity(rVal, new Vector3d(1,-1,1)); + ServerEntityUtils.repositionEntity(rVal, new Vector3d(1,-1,1)); return rVal; } diff --git a/src/main/java/electrosphere/game/client/ClientFunctions.java b/src/main/java/electrosphere/game/client/ClientFunctions.java index 4d071cdc..0857af65 100644 --- a/src/main/java/electrosphere/game/client/ClientFunctions.java +++ b/src/main/java/electrosphere/game/client/ClientFunctions.java @@ -19,21 +19,15 @@ public class ClientFunctions { public static void runBeforeSimulationFunctions(){ //cell tracking values - if(Globals.RUN_CLIENT){ - if(Globals.playerEntity != null){ - oldPlayerCharacterPosition = new Vector3d(EntityUtils.getPosition(Globals.playerEntity)); - } + if(Globals.playerEntity != null){ + oldPlayerCharacterPosition = new Vector3d(EntityUtils.getPosition(Globals.playerEntity)); } } public static void runClientFunctions(){ - if(Globals.clientTerrainManager != null){ - Globals.clientTerrainManager.handleMessages(); - Globals.clientTerrainManager.ejectLoadedChunks(); - } ClientTerrainManager.generateTerrainChunkGeometry(); updateSkyboxPos(); - updateCellManager(); + // updateCellManager(); } static void updateSkyboxPos(){ @@ -48,11 +42,19 @@ public class ClientFunctions { } } + public static void loadTerrain(){ + if(Globals.clientTerrainManager != null){ + Globals.clientTerrainManager.handleMessages(); + Globals.clientTerrainManager.ejectLoadedChunks(); + updateCellManager(); + } + } + static void updateCellManager(){ /// /// C L I E N T C E L L M A N A G E R /// - if(Globals.drawCellManager != null){ + if(Globals.drawCellManager != null && Globals.clientWorldData != null){ if(Globals.playerEntity != null){ newPlayerCharacterPosition = EntityUtils.getPosition(Globals.playerEntity); } diff --git a/src/main/java/electrosphere/game/client/cells/DrawCell.java b/src/main/java/electrosphere/game/client/cells/DrawCell.java index 2f1cc3ff..974c77bb 100644 --- a/src/main/java/electrosphere/game/client/cells/DrawCell.java +++ b/src/main/java/electrosphere/game/client/cells/DrawCell.java @@ -4,6 +4,7 @@ import electrosphere.collision.dispatch.CollisionObject; import electrosphere.dynamics.RigidBody; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; import electrosphere.game.collision.PhysicsUtils; @@ -97,7 +98,7 @@ public class DrawCell { */ public void generateDrawableEntity(int stride){ if(modelEntity != null){ - Globals.entityManager.deregisterEntity(modelEntity); + Globals.clientScene.deregisterEntity(modelEntity); } Model terrainModel = RenderUtils.createMinimizedTerrainModelPrecomputedShader(heightmap, texturemap, program, stride); Mesh terrainMesh = terrainModel.meshes.get(0); @@ -112,7 +113,8 @@ public class DrawCell { uniformList.add("groundTextures[2]"); uniformList.add("groundTextures[3]"); String terrainModelPath = Globals.assetManager.registerModel(terrainModel); - modelEntity = EntityUtils.spawnDrawableEntity(terrainModelPath); + modelEntity = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(modelEntity, terrainModelPath); EntityUtils.getActor(modelEntity).addTextureMask(new ActorTextureMask("terrain",textureList,uniformList)); modelEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); modelEntity.putData(EntityDataStrings.DRAW_CAST_SHADOW, true); @@ -121,25 +123,25 @@ public class DrawCell { } public void retireCell(){ - EntityUtils.cleanUpDrawableEntity(modelEntity); + EntityUtils.cleanUpEntity(modelEntity); } public void generatePhysics(){ //if we're in no-graphics mode, need to generate the entity if(modelEntity == null){ - modelEntity = EntityUtils.spawnSpatialEntity(); + modelEntity = EntityCreationUtils.createClientSpatialEntity(); modelEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); EntityUtils.getPosition(modelEntity).set(new Vector3f(cellX * dynamicInterpolationRatio, 0.0f, cellY * dynamicInterpolationRatio)); } //then actually perform the attach - physicsObject = PhysicsUtils.attachTerrainRigidBody(modelEntity,heightmap); - Globals.collisionEngine.registerPhysicsEntity(modelEntity); + physicsObject = PhysicsUtils.attachTerrainRigidBody(modelEntity,heightmap,false); + Globals.clientSceneWrapper.getCollisionEngine().registerPhysicsEntity(modelEntity); // System.out.println("generate physics"); } public void destroyPhysics(){ - Globals.collisionEngine.deregisterCollidableEntity(modelEntity); - Globals.collisionEngine.deregisterRigidBody((RigidBody)physicsObject); + Globals.clientSceneWrapper.getCollisionEngine().deregisterCollidableEntity(modelEntity); + Globals.clientSceneWrapper.getCollisionEngine().deregisterRigidBody((RigidBody)physicsObject); } } diff --git a/src/main/java/electrosphere/game/client/cells/DrawCellManager.java b/src/main/java/electrosphere/game/client/cells/DrawCellManager.java index 00350646..dd4e115b 100644 --- a/src/main/java/electrosphere/game/client/cells/DrawCellManager.java +++ b/src/main/java/electrosphere/game/client/cells/DrawCellManager.java @@ -72,7 +72,13 @@ public class DrawCellManager { boolean generateDrawables = false; - + /** + * DrawCellManager constructor + * @param commonWorldData The common world data + * @param clientTerrainManager The client terrain manager + * @param discreteX The initial discrete position X coordinate + * @param discreteY The initial discrete position Y coordinate + */ public DrawCellManager(CommonWorldData commonWorldData, ClientTerrainManager clientTerrainManager, int discreteX, int discreteY){ this.commonWorldData = commonWorldData; worldBoundDiscreteMax = (int)(commonWorldData.getWorldBoundMin().x / commonWorldData.getDynamicInterpolationRatio() * 1.0f); diff --git a/src/main/java/electrosphere/game/client/player/ClientPlayerData.java b/src/main/java/electrosphere/game/client/player/ClientPlayerData.java index ae53e958..291c9255 100644 --- a/src/main/java/electrosphere/game/client/player/ClientPlayerData.java +++ b/src/main/java/electrosphere/game/client/player/ClientPlayerData.java @@ -1,10 +1,11 @@ package electrosphere.game.client.player; +import org.joml.Vector3i; + import electrosphere.logger.LoggerInterface; public class ClientPlayerData { - int worldPositionX; - int worldPositionY; + Vector3i worldPos; int simulationRadius = 3; boolean loaded = false; @@ -16,19 +17,14 @@ public class ClientPlayerData { return loaded; } - public void setWorldPosition(int x, int y){ - worldPositionX = x; - worldPositionY = y; + public void setWorldPos(Vector3i worldPos){ + this.worldPos = worldPos; LoggerInterface.loggerGameLogic.INFO("Loaded client data"); loaded = true; } - public int getWorldPositionX() { - return worldPositionX; - } - - public int getWorldPositionY() { - return worldPositionY; + public Vector3i getWorldPos() { + return worldPos; } diff --git a/src/main/java/electrosphere/game/client/targeting/crosshair/Crosshair.java b/src/main/java/electrosphere/game/client/targeting/crosshair/Crosshair.java index f09ac96f..7d9fe446 100644 --- a/src/main/java/electrosphere/game/client/targeting/crosshair/Crosshair.java +++ b/src/main/java/electrosphere/game/client/targeting/crosshair/Crosshair.java @@ -2,6 +2,7 @@ package electrosphere.game.client.targeting.crosshair; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.camera.CameraEntityUtils; @@ -23,7 +24,8 @@ public class Crosshair { static boolean crosshairActive = false; public static void initCrossHairEntity(){ - crossHairEntity = EntityUtils.spawnDrawableEntity("/Models/lockoncrosshair1.fbx"); + crossHairEntity = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(crossHairEntity, "/Models/lockoncrosshair1.fbx"); EntityUtils.setVisible(crossHairEntity, false); } @@ -36,7 +38,7 @@ public class Crosshair { if(!crosshairActive){ Entity target = null; double dist = 100; - for(Entity entity : Globals.entityManager.getEntitiesWithTag(EntityTags.TARGETABLE)){ + for(Entity entity : Globals.clientScene.getEntitiesWithTag(EntityTags.TARGETABLE)){ Vector3d entityPos = EntityUtils.getPosition(entity); double currentDist = parentPos.distance(entityPos); double currentAngleDiff = new Vector3d(entityPos).sub(parentPos).normalize().dot(new Vector3d(CameraEntityUtils.getCameraEye(Globals.playerCamera))); diff --git a/src/main/java/electrosphere/game/client/terrain/cache/ClientTerrainCache.java b/src/main/java/electrosphere/game/client/terrain/cache/ClientTerrainCache.java index b9048751..0eebcec3 100644 --- a/src/main/java/electrosphere/game/client/terrain/cache/ClientTerrainCache.java +++ b/src/main/java/electrosphere/game/client/terrain/cache/ClientTerrainCache.java @@ -27,9 +27,8 @@ public class ClientTerrainCache { List cacheList = new CopyOnWriteArrayList(); - public ClientTerrainCache(int cacheSize, ClientWorldData clientWorldData){ + public ClientTerrainCache(int cacheSize){ this.cacheSize = cacheSize; - this.clientWorldData = clientWorldData; } // TerrainChunkValues getChunkValuesAtPoint(int x, int y){ @@ -50,7 +49,7 @@ public class ClientTerrainCache { //USED TO ADD macro values public void addChunkValuesToCache(int x, int y, float[][] macroValues, long[][] randomizer){ // TerrainChunkValues chunk = new TerrainChunkValues(macroValues, randomizer); - + assert clientWorldData != null; float[][] heightmap = TerrainInterpolator.getBicubicInterpolatedChunk( macroValues, @@ -93,4 +92,11 @@ public class ClientTerrainCache { public float[][] getHeightmapAtChunkPoint(int x, int y){ return cacheMap.get(getKey(x,y)); } + + + + + public void setClientWorldData(ClientWorldData clientWorldData){ + this.clientWorldData = clientWorldData; + } } diff --git a/src/main/java/electrosphere/game/client/terrain/manager/ClientTerrainManager.java b/src/main/java/electrosphere/game/client/terrain/manager/ClientTerrainManager.java index ab139d45..515c8a7e 100644 --- a/src/main/java/electrosphere/game/client/terrain/manager/ClientTerrainManager.java +++ b/src/main/java/electrosphere/game/client/terrain/manager/ClientTerrainManager.java @@ -38,9 +38,8 @@ public class ClientTerrainManager { static List terrainChunkGenerationQueue = new CopyOnWriteArrayList(); - public ClientTerrainManager(ClientWorldData clientWorldData){ - this.clientWorldData = clientWorldData; - terrainCache = new ClientTerrainCache(CACHE_SIZE,clientWorldData); + public ClientTerrainManager(){ + terrainCache = new ClientTerrainCache(CACHE_SIZE); loadingChunkCache = new LoadingChunkCache(); } @@ -116,14 +115,18 @@ public class ClientTerrainManager { } break; case CHUNKLOADSTART: - LoadingChunk newChunk = new LoadingChunk(message.getworldX(),message.getworldY(),(int)message.getvalue(),clientWorldData); - loadingChunkCache.addLoadingChunkToCache(newChunk); - newChunk.incrementMessageCount(); + if(clientWorldData != null){ + LoadingChunk newChunk = new LoadingChunk(message.getworldX(),message.getworldY(),(int)message.getvalue(),clientWorldData); + loadingChunkCache.addLoadingChunkToCache(newChunk); + newChunk.incrementMessageCount(); + } else { + bouncedMessages.add(message); + } break; case HEIGHTMAPMODIFICATION: if(loadingChunkCache.containsKey(loadingChunkCache.getKey(message.getworldX(), message.getworldY()))){ LoadingChunk inProgressChunk = loadingChunkCache.fetch(loadingChunkCache.getKey(message.getworldX(), message.getworldY())); - inProgressChunk.addModification(message.getworldX(), message.getworldY(), message.getlocationX(), message.getlocationY(), message.getvalue()); + inProgressChunk.addModification(message.getworldX(), message.getworldZ(), message.getlocationX(), message.getlocationZ(), message.getvalue()); inProgressChunk.incrementMessageCount(); } else { bouncedMessages.add(message); @@ -148,6 +151,7 @@ public class ClientTerrainManager { } public boolean containsHeightmapAtRealPoint(double x, double z){ + assert clientWorldData != null; return terrainCache.containsHeightmapAtChunkPoint(clientWorldData.convertRealToChunkSpace(x), clientWorldData.convertRealToChunkSpace(z)); } @@ -157,6 +161,7 @@ public class ClientTerrainManager { public double getHeightAtPosition(double x, double y){ + assert clientWorldData != null; //get chunk coordinate space of input x,y int chunkX = (int)Math.floor(x / clientWorldData.getDynamicInterpolationRatio()); int chunkY = (int)Math.floor(y / clientWorldData.getDynamicInterpolationRatio()); @@ -194,6 +199,7 @@ public class ClientTerrainManager { } public float[][] getTextureMapAtPoint(int x, int y){ + assert clientWorldData != null; float[][] rVal = new float[clientWorldData.getDynamicInterpolationRatio()][clientWorldData.getDynamicInterpolationRatio()]; rVal[1][1] = 1; rVal[2][1] = 1; @@ -207,16 +213,18 @@ public class ClientTerrainManager { } public void ejectLoadedChunks(){ - List chunksToEject = new LinkedList(); - for(LoadingChunk chunk : loadingChunkCache.getChunks()){ - if(chunk.isComplete() && chunk.getClientWorldData() != null){ - float[][] heightMap = chunk.exportFloats(); - terrainCache.addFloatsToCache(chunk.getWorldX(), chunk.getWorldY(), heightMap); - chunksToEject.add(chunk); + if(clientWorldData != null){ + List chunksToEject = new LinkedList(); + for(LoadingChunk chunk : loadingChunkCache.getChunks()){ + if(chunk.isComplete() && chunk.getClientWorldData() != null){ + float[][] heightMap = chunk.exportFloats(); + terrainCache.addFloatsToCache(chunk.getWorldX(), chunk.getWorldY(), heightMap); + chunksToEject.add(chunk); + } + } + for(LoadingChunk loadedChunk : chunksToEject){ + loadingChunkCache.remove(loadedChunk); } - } - for(LoadingChunk loadedChunk : chunksToEject){ - loadingChunkCache.remove(loadedChunk); } } @@ -236,5 +244,14 @@ public class ClientTerrainManager { } terrainChunkGenerationQueue.clear(); } + + /** + * Sets the client world data that this terrain manager references + * @param clientWorldData The client world data + */ + public void setClientWorldData(ClientWorldData clientWorldData){ + this.clientWorldData = clientWorldData; + this.terrainCache.setClientWorldData(clientWorldData); + } } diff --git a/src/main/java/electrosphere/game/collision/CollisionEngine.java b/src/main/java/electrosphere/game/collision/CollisionEngine.java index 7b784a4d..35282bf5 100644 --- a/src/main/java/electrosphere/game/collision/CollisionEngine.java +++ b/src/main/java/electrosphere/game/collision/CollisionEngine.java @@ -359,11 +359,11 @@ public class CollisionEngine { /* Check if the entity is being accelerated by gravity */ - public boolean gravityCheck(CommonWorldData w, Entity e){ - double worldHeight = w.getElevationAtPoint(EntityUtils.getPosition(e)); - double entityHeight = EntityUtils.getPosition(e).y; - return entityHeight > worldHeight + 0.1f; - } + // public boolean gravityCheck(CommonWorldData w, Entity e){ + // double worldHeight = w.getElevationAtPoint(EntityUtils.getPosition(e)); + // double entityHeight = EntityUtils.getPosition(e).y; + // return entityHeight > worldHeight + 0.1f; + // } public float sweepTest(CollisionObject object, Vector3f startPos, Vector3f endPos){ SphereShape sphere = new SphereShape(0.1f); diff --git a/src/main/java/electrosphere/game/collision/PhysicsUtils.java b/src/main/java/electrosphere/game/collision/PhysicsUtils.java index 89254f5e..0f372ab4 100644 --- a/src/main/java/electrosphere/game/collision/PhysicsUtils.java +++ b/src/main/java/electrosphere/game/collision/PhysicsUtils.java @@ -11,6 +11,7 @@ import electrosphere.dynamics.RigidBodyConstructionInfo; import electrosphere.engine.Globals; import electrosphere.linearmath.DefaultMotionState; import electrosphere.linearmath.Transform; +import electrosphere.server.datacell.Realm; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; @@ -49,7 +50,7 @@ public class PhysicsUtils { } - public static RigidBody attachTerrainRigidBody(Entity terrain, float[][] heightfield){ + public static RigidBody attachTerrainRigidBody(Entity terrain, float[][] heightfield, boolean isServer){ Vector3d position = EntityUtils.getPosition(terrain); @@ -165,8 +166,12 @@ public class PhysicsUtils { // terrainRigidBody.setFriction(1f); - - Globals.collisionEngine.registerCollisionObject(terrainRigidBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); + if(isServer){ + Realm terrainRealm = Globals.realmManager.getEntityRealm(terrain); + terrainRealm.getCollisionEngine().registerCollisionObject(terrainRigidBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); + } else { + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(terrainRigidBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); + } // terrainRigidBody.getAabb(aabbMin, aabbMax); // @@ -180,7 +185,7 @@ public class PhysicsUtils { } - public static RigidBody attachTerrainChunkRigidBody(Entity terrain, TerrainChunkData data){ + public static RigidBody clientAttachTerrainChunkRigidBody(Entity terrain, TerrainChunkData data){ Vector3d position = EntityUtils.getPosition(terrain); @@ -270,7 +275,111 @@ public class PhysicsUtils { // terrainRigidBody.setFriction(1f); - Globals.collisionEngine.registerCollisionObject(terrainRigidBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); + Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(terrainRigidBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); + +// terrainRigidBody.getAabb(aabbMin, aabbMax); +// +// System.out.println("aabbMin: " + aabbMin + " aabbMax: " + aabbMax); + + + terrain.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, terrainRigidBody); + + return terrainRigidBody; + + } + + + public static RigidBody serverAttachTerrainChunkRigidBody(Entity terrain, TerrainChunkData data){ + + Vector3d position = EntityUtils.getPosition(terrain); + + + float collisionMargin = 0.08f; + + /* + Traditional buffer code not working for some reason + the approach of + https://stackoverflow.com/questions/40855945/lwjgl-mesh-to-jbullet-collider + works much better + IDK why + */ + + int numberTriangles = data.getFaceElements().size() / 3; + int triangleStride = 0; + + int numberVertices = data.getVertices().size() / 3; + int vertexStride = 0; + + float[] vertices = new float[numberVertices * 3]; + int vertexInserterPos = 0; + int[] indices = new int[numberTriangles * 3]; + int indexInserterPos = 0; + + for(float vertexValue : data.getVertices()){ + vertices[vertexInserterPos] = vertexValue; + vertexInserterPos++; + } + + for(int element : data.getFaceElements()){ + indices[indexInserterPos] = element; + indexInserterPos++; + } + + + javax.vecmath.Vector3f aabbMin = new javax.vecmath.Vector3f(); + javax.vecmath.Vector3f aabbMax = new javax.vecmath.Vector3f(); + + + + + //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/IndexedMesh.html + electrosphere.collision.shapes.IndexedMesh indexedMesh = new electrosphere.collision.shapes.IndexedMesh(); + + indexedMesh.numTriangles = indices.length / 3; + indexedMesh.triangleIndexBase = ByteBuffer.allocateDirect(indices.length*Float.BYTES).order(ByteOrder.nativeOrder()); + indexedMesh.triangleIndexBase.asIntBuffer().put(indices); + indexedMesh.triangleIndexStride = 3 * Float.BYTES; + + indexedMesh.numVertices = vertices.length / 3; + indexedMesh.vertexBase = ByteBuffer.allocateDirect(vertices.length*Float.BYTES).order(ByteOrder.nativeOrder()); + indexedMesh.vertexBase.asFloatBuffer().put(vertices); + indexedMesh.vertexStride = 3 * Float.BYTES; + + + + + + + //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shpaes/TriangleIndexVertexArray.html + electrosphere.collision.shapes.TriangleIndexVertexArray triangleIndexArray = new electrosphere.collision.shapes.TriangleIndexVertexArray(); + triangleIndexArray.addIndexedMesh(indexedMesh); //this assumes the scalar type is integer (assumes bytebuffer is actually integer +// triangleIndexArray.calculateAabbBruteForce(aabbMin, aabbMax); + + + + //http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/BvhTriangleMeshShape.html + electrosphere.collision.shapes.BvhTriangleMeshShape terrainShape = new electrosphere.collision.shapes.BvhTriangleMeshShape( + triangleIndexArray, + true // "useQuantizedAabbCompression" -- apparently means better memory usage ( http://jbullet.advel.cz/javadoc/com/bulletphysics/collision/shapes/BvhTriangleMeshShape.html ) + ); + + //uncomment if we start falling through things again + terrainShape.setMargin(collisionMargin); + +// terrainShape.localGetSupportingVertex(new javax.vecmath.Vector3f(1,0,0), aabbMin); +// terrainShape.recalcLocalAabb(); +// terrainShape.getLocalAabbMin(aabbMin); +// terrainShape.getLocalAabbMax(aabbMax); + + + DefaultMotionState defaultMotionState = new DefaultMotionState(new Transform(new javax.vecmath.Matrix4f(new javax.vecmath.Quat4f(0,0,0,1),new javax.vecmath.Vector3f((float)position.x,(float)position.y,(float)position.z),1.0f))); + RigidBodyConstructionInfo terrainRigidBodyCI = new RigidBodyConstructionInfo(0, defaultMotionState, terrainShape); + RigidBody terrainRigidBody = new RigidBody(terrainRigidBodyCI); + +// terrainRigidBody.setFriction(1f); + + Realm terrainRealm = Globals.realmManager.getEntityRealm(terrain); + terrainRealm.getCollisionEngine().registerCollisionObject(terrainRigidBody, new Collidable(terrain,Collidable.TYPE_TERRAIN)); // terrainRigidBody.getAabb(aabbMin, aabbMax); // diff --git a/src/main/java/electrosphere/game/server/effects/ParticleEffects.java b/src/main/java/electrosphere/game/server/effects/ParticleEffects.java index e9fb814a..8e924a8c 100644 --- a/src/main/java/electrosphere/game/server/effects/ParticleEffects.java +++ b/src/main/java/electrosphere/game/server/effects/ParticleEffects.java @@ -20,7 +20,7 @@ public class ParticleEffects { Vector3f direction = new Vector3f(rand.nextFloat() - 0.5f,rand.nextFloat() - 0.5f,rand.nextFloat() - 0.5f).normalize(); float velocity = rand.nextFloat() * 0.01f; float acceleration = 0.005f; - Entity spark = ParticleUtils.spawnBillboardProjectileParticle("Textures/spark1.png", 15, direction, velocity, acceleration); + Entity spark = ParticleUtils.clientSpawnBillboardProjectileParticle("Textures/spark1.png", 15, direction, velocity, acceleration); EntityUtils.getPosition(spark).set(position); EntityUtils.getScale(spark).mul(0.03f); } @@ -33,7 +33,7 @@ public class ParticleEffects { Vector3f direction = new Vector3f(rand.nextFloat() - 0.5f,rand.nextFloat() - 0.5f,rand.nextFloat() - 0.5f).normalize(); float velocity = rand.nextFloat() * 0.001f; float acceleration = 0.000005f; - Entity spark = ParticleUtils.spawnBillboardProjectileParticle("Textures/bloodsplat1.png", 90, direction, velocity, acceleration); + Entity spark = ParticleUtils.clientSpawnBillboardProjectileParticle("Textures/bloodsplat1.png", 90, direction, velocity, acceleration); EntityUtils.getPosition(spark).set(position); EntityUtils.getScale(spark).mul(0.1f); } diff --git a/src/main/java/electrosphere/game/server/structure/virtual/VirtualStructureUtils.java b/src/main/java/electrosphere/game/server/structure/virtual/VirtualStructureUtils.java index 3261ec37..b2a6afae 100644 --- a/src/main/java/electrosphere/game/server/structure/virtual/VirtualStructureUtils.java +++ b/src/main/java/electrosphere/game/server/structure/virtual/VirtualStructureUtils.java @@ -4,10 +4,13 @@ import electrosphere.engine.Globals; import electrosphere.entity.types.structure.StructureUtils; import electrosphere.game.data.structure.type.model.StructureType; import electrosphere.game.server.character.Character; +import electrosphere.server.datacell.Realm; + import java.util.LinkedList; import java.util.List; import org.joml.Quaternionf; import org.joml.Vector2f; +import org.joml.Vector3d; import org.joml.Vector3f; /** @@ -37,7 +40,8 @@ public class VirtualStructureUtils { Globals.serverTerrainManager.deformTerrainAtLocationToValue(newWorldX, newWorldY, (int)(newLocationX), (int)(newLocationY), (float)centerHeight); } } - StructureUtils.spawnBasicStructure(type, new Vector3f(posX,(float)centerHeight + 2.4f,posY), new Quaternionf()); + Realm realm = Globals.realmManager.getRealms().iterator().next(); + StructureUtils.serverSpawnBasicStructure(type, realm, new Vector3d(posX,(float)centerHeight + 2.4f,posY), new Quaternionf()); return rVal; } diff --git a/src/main/java/electrosphere/game/server/unit/UnitUtils.java b/src/main/java/electrosphere/game/server/unit/UnitUtils.java deleted file mode 100644 index af014c57..00000000 --- a/src/main/java/electrosphere/game/server/unit/UnitUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -package electrosphere.game.server.unit; - -import electrosphere.entity.Entity; -import electrosphere.entity.EntityUtils; -import electrosphere.entity.types.attach.AttachUtils; -import electrosphere.entity.types.collision.CollisionObjUtils; -import electrosphere.entity.types.creature.CreatureUtils; -import electrosphere.entity.types.item.ItemUtils; -import electrosphere.server.ai.creature.MillAbout; - -import org.joml.Quaterniond; -import org.joml.Quaternionf; -import org.joml.Vector3d; -import org.joml.Vector3f; - -/** - * - * @author amaterasu - */ -public class UnitUtils { - - public static void spawnTextGoblin(float posX, float posY, float posZ){ - Entity goblin = CreatureUtils.spawnBasicCreature("Goblin",null); - CollisionObjUtils.positionCharacter(goblin, new Vector3d(posX, posY, posZ)); - EntityUtils.getScale(goblin).set(0.005f); - //give evil goblin sword - Entity goblinSword = ItemUtils.spawnBasicItem("Katana"); - AttachUtils.attachEntityToEntityAtBone(goblin, goblinSword, "Bone.031", new Quaternionf()); - //attach ai to evil goblin - MillAbout.attachToCreature(goblin); -// MindlessAttacker.attachToCreature(goblin); - } - -} diff --git a/src/main/java/electrosphere/game/server/world/ServerWorldData.java b/src/main/java/electrosphere/game/server/world/ServerWorldData.java index f9a62873..e8ec954e 100644 --- a/src/main/java/electrosphere/game/server/world/ServerWorldData.java +++ b/src/main/java/electrosphere/game/server/world/ServerWorldData.java @@ -41,6 +41,7 @@ public class ServerWorldData { Vector3f worldMaxPoint; int worldSizeDiscrete; + int worldSizeDiscreteVertical; int dynamicInterpolationRatio; float randomDampener; boolean isArena = false; @@ -52,6 +53,7 @@ public class ServerWorldData { rVal.worldMaxPoint = new Vector3f(200,0,200); rVal.dynamicInterpolationRatio = 100; rVal.worldSizeDiscrete = 2; + rVal.worldSizeDiscreteVertical = 1; rVal.randomDampener = 0.0f; rVal.isArena = true; return rVal; @@ -67,6 +69,7 @@ public class ServerWorldData { rVal.dynamicInterpolationRatio = terrainManager.getDynamicInterpolationRatio(); rVal.worldSizeDiscrete = terrainManager.getWorldDiscreteSize(); + rVal.worldSizeDiscreteVertical = 128; rVal.randomDampener = terrainManager.getRandomDampener(); return rVal; diff --git a/src/main/java/electrosphere/logger/LoggerInterface.java b/src/main/java/electrosphere/logger/LoggerInterface.java index 846a33f1..a75e9af0 100644 --- a/src/main/java/electrosphere/logger/LoggerInterface.java +++ b/src/main/java/electrosphere/logger/LoggerInterface.java @@ -21,11 +21,11 @@ public class LoggerInterface { public static void initLoggers(){ loggerStartup = new Logger(LogLevel.WARNING); - loggerNetworking = new Logger(LogLevel.WARNING); + loggerNetworking = new Logger(LogLevel.DEBUG); loggerFileIO = new Logger(LogLevel.WARNING); loggerGameLogic = new Logger(LogLevel.WARNING); loggerRenderer = new Logger(LogLevel.WARNING); - loggerEngine = new Logger(LogLevel.WARNING); + loggerEngine = new Logger(LogLevel.DEBUG); loggerAuth = new Logger(LogLevel.WARNING); loggerDB = new Logger(LogLevel.WARNING); loggerStartup.INFO("Initialized loggers"); diff --git a/src/main/java/electrosphere/menu/MenuCallbacks.java b/src/main/java/electrosphere/menu/MenuCallbacks.java deleted file mode 100644 index b86320b3..00000000 --- a/src/main/java/electrosphere/menu/MenuCallbacks.java +++ /dev/null @@ -1,357 +0,0 @@ -package electrosphere.menu; - -import electrosphere.audio.AudioSource; -import electrosphere.audio.AudioUtils; -import electrosphere.controls.ControlHandler; -import electrosphere.controls.ControlHandler.ControlsState; -import electrosphere.engine.Globals; -import electrosphere.engine.LoadingThread; -import electrosphere.engine.Main; -import electrosphere.net.NetUtils; -import electrosphere.net.client.ClientNetworking; -import electrosphere.renderer.ui.DrawableElement; -import electrosphere.renderer.ui.elements.Label; -import electrosphere.server.saves.SaveUtils; - -import org.joml.Vector3f; - -/** - * - * @author amaterasu - */ -public class MenuCallbacks { -// public static void selectOption(Menu m){ -// switch(m.getType()){ -// case TITLE_MENU: -// switch(((TextBox)m.getCurrentOption()).getText()){ -// //single player -// case "SINGLEPLAYER": -// // m.dispose(); -// // Globals.loadingThread = new LoadingThread(LoadingThread.LOAD_MAIN_GAME); -// // Globals.RUN_CLIENT = true; -// // Globals.RUN_SERVER = true; -// // Globals.loadingThread.start(); -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createWorldSelectMenu(); -// break; -// //multi player -// case "MULTIPLAYER": -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createMultiplayerMenu(); -// break; -// //arena -// case "ARENA": -// m.dispose(); -// Globals.loadingThread = new LoadingThread(LoadingThread.LOAD_ARENA); -// Globals.RUN_CLIENT = true; -// Globals.RUN_SERVER = true; -// Globals.loadingThread.start(); -// break; -// //options -// case "OPTIONS": -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createOptionsMainMenu(); -// break; -// //test -// case "UI TESTING": -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createTestMainMenu(); -// break; -// } -// break; -// case WORLD_SELECT_MENU: -// switch(((TextBox)m.getCurrentOption()).getText()){ -// case "CREATE WORLD": -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createWorldCreationMenu(); -// break; -// default: -// String worldName = ((TextBox)m.getCurrentOption()).getText(); -// m.dispose(); -// //check if has save or not -// if(SaveUtils.worldHasSave(worldName.toLowerCase())){ -// Globals.loadingThread = new LoadingThread(LoadingThread.LOAD_MAIN_GAME); -// Globals.RUN_CLIENT = true; -// Globals.RUN_SERVER = true; -// Globals.loadingThread.start(); -// } else { -// Globals.currentSaveName = worldName.toLowerCase(); -// SaveUtils.loadTerrainAndCreateWorldData(); -// Globals.currentMenu = MenuGenerators.createSaveCreationMenu(); -// } -// break; -// } -// break; -// case WORLD_CREATE_MENU: -// break; -// case SAVE_CREATE_MENU: -// switch(((TextBox)m.getCurrentOption()).getText()){ -// case "SAVE": -// m.dispose(); -// SaveUtils.saveWorldDataToSave(Globals.currentSaveName); -// Globals.currentMenu = MenuGenerators.createWorldSelectMenu(); -// break; -// case "CANCEL": -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createWorldSelectMenu(); -// break; -// } -// break; -// case CHARACTER_CREATE_MENU: -// break; -// case FINALIZE_SAVE_CREATION_MENU: -// break; -// case MULTIPLAYER_MENU: -// switch(((TextBox)m.getCurrentOption()).getText()){ -// //HOST -// case "HOST": -// m.dispose(); -// Globals.loadingThread = new LoadingThread(LoadingThread.LOAD_MAIN_GAME); -// Globals.RUN_CLIENT = true; -// Globals.RUN_SERVER = true; -// Globals.loadingThread.start(); -// break; -// //JOIN -// case "JOIN": -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createIPMenu(); -// break; -// //back -// case "BACK": -// backout(m); -// break; - -// } -// break; -// case IP_MENU: -// switch(((TextBox)m.getCurrentOption()).getText()){ -// //connect -// case "CONNECT": -// NetUtils.setAddress( ( (TextBox)m.getOptions().get(0) ).getText() ); -// NetUtils.setPort( Integer.parseInt( ( (TextBox)m.getOptions().get(1) ).getText() ) ); -// m.dispose(); -// Globals.loadingThread = new LoadingThread(LoadingThread.LOAD_MAIN_GAME); -// Globals.RUN_CLIENT = true; -// Globals.RUN_SERVER = false; -// Globals.loadingThread.start(); -// break; -// //back -// case "BACK": -// backout(m); -// break; -// } -// break; -// case IN_GAME_MAIN_MENU: -// switch(((Label)m.getCurrentOption()).getText()){ -// //connect -// case "QUIT": -// //TODO: actually shut down program -// Globals.ENGINE_SHUTDOWN_FLAG = true; -// break; -// //back -// case "BACK": -// MenuGenerators.makeMenuUndrawable(Globals.currentMenu); -// Globals.currentMenu.dispose(); -// Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); -// break; -// } -// break; -// } -// } - -// public static void backout(Menu m){ -// AudioSource startupSound = AudioUtils.playAudioAtLocation("/Audio/MenuBackspace.ogg", new Vector3f(0,0,0)); -// switch(m.getType()){ -// case TITLE_MENU: -// Main.running = false; -// break; -// case WORLD_SELECT_MENU: -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createTitleMenu(); -// break; -// case WORLD_CREATE_MENU: -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createWorldSelectMenu(); -// break; -// case SAVE_CREATE_MENU: -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createWorldSelectMenu(); -// break; -// case CHARACTER_CREATE_MENU: -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createSaveCreationMenu(); -// break; -// case FINALIZE_SAVE_CREATION_MENU: -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createCharacterCreationMenu(); -// break; -// case MULTIPLAYER_MENU: -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createTitleMenu(); -// break; -// case IP_MENU: -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createMultiplayerMenu(); -// break; -// case OPTIONS_MAIN_MENU: -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createTitleMenu(); -// break; -// case TEST: -// m.dispose(); -// Globals.currentMenu = MenuGenerators.createTitleMenu(); -// break; -// case IN_GAME_MAIN_MENU: -// MenuGenerators.makeMenuUndrawable(Globals.currentMenu); -// Globals.currentMenu.dispose(); -// Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); -// break; -// case INVENTORY_NATURAL: -// MenuGenerators.makeMenuUndrawable(Globals.currentMenu); -// Globals.currentMenu.dispose(); -// Globals.controlHandler.setHandlerState(ControlsState.MAIN_GAME); -// Globals.controlHandler.hideMouse(); -// break; -// } -// } - -// public static void menuHandleKeypress(Menu m, String keycode){ -// char toWrite = ' '; -// DrawableElement currentOption = m.getCurrentOption(); -// boolean backspace = false; -// switch(keycode){ -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_BACKSPACE: -// if(currentOption instanceof TextBox){ -// TextBox currentTextBox = (TextBox)currentOption; -// String currentText = currentTextBox.getText(); -// if(currentText.length() > 0){ -// currentTextBox.setText(currentText.substring(0, currentText.length() - 1)); -// AudioSource startupSound = AudioUtils.playAudioAtLocation("/Audio/MenuBackspace.ogg", new Vector3f(0,0,0)); -// } -// } -// backspace = true; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_0: -// toWrite = '0'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_1: -// toWrite = '1'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_2: -// toWrite = '2'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_3: -// toWrite = '3'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_4: -// toWrite = '4'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_5: -// toWrite = '5'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_6: -// toWrite = '6'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_7: -// toWrite = '7'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_8: -// toWrite = '8'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_9: -// toWrite = '9'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_A: -// toWrite = 'A'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_B: -// toWrite = 'B'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_C: -// toWrite = 'C'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_D: -// toWrite = 'D'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_E: -// toWrite = 'E'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_F: -// toWrite = 'F'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_G: -// toWrite = 'G'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_H: -// toWrite = 'H'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_I: -// toWrite = 'I'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_J: -// toWrite = 'J'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_K: -// toWrite = 'K'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_L: -// toWrite = 'L'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_M: -// toWrite = 'M'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_N: -// toWrite = 'N'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_O: -// toWrite = 'O'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_P: -// toWrite = 'P'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_Q: -// toWrite = 'Q'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_R: -// toWrite = 'R'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_S: -// toWrite = 'S'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_T: -// toWrite = 'T'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_U: -// toWrite = 'U'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_V: -// toWrite = 'V'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_W: -// toWrite = 'W'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_X: -// toWrite = 'X'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_Y: -// toWrite = 'Y'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_Z: -// toWrite = 'Z'; -// break; -// case ControlHandler.DATA_STRING_INPUT_CODE_MENU_TYPE_PERIOD: -// toWrite = '.'; -// break; -// } -// if(!backspace){ -// if(currentOption instanceof TextBox){ -// TextBox currentTextBox = (TextBox)currentOption; -// String currentText = currentTextBox.getText(); -// if(currentText.length() < currentTextBox.getCols()){ -// currentTextBox.setText(currentText + toWrite); -// AudioSource startupSound = AudioUtils.playAudioAtLocation("/Audio/MenuType.ogg", new Vector3f(0,0,0)); -// } -// } -// } -// } -} diff --git a/src/main/java/electrosphere/menu/MenuGenerators.java b/src/main/java/electrosphere/menu/MenuGenerators.java index 23e0b49b..a03bd7d1 100644 --- a/src/main/java/electrosphere/menu/MenuGenerators.java +++ b/src/main/java/electrosphere/menu/MenuGenerators.java @@ -7,8 +7,8 @@ import org.joml.Vector3f; import electrosphere.auth.AuthenticationManager; import electrosphere.controls.ControlHandler.ControlsState; import electrosphere.engine.Globals; -import electrosphere.engine.LoadingThread; import electrosphere.engine.Main; +import electrosphere.engine.loadingthreads.LoadingThread; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityUtils; @@ -83,7 +83,7 @@ public class MenuGenerators { clientThread.start(); } else { Globals.currentSaveName = saveName.toLowerCase(); - SaveUtils.loadTerrainAndCreateWorldData(); + SaveUtils.loadTerrainAndCreateWorldData(saveName.toLowerCase()); WindowUtils.replaceMainMenuContents(MenuGenerators.createSaveCreationMenu()); } return false; diff --git a/src/main/java/electrosphere/menu/MenuGeneratorsArena.java b/src/main/java/electrosphere/menu/MenuGeneratorsArena.java index 3893d3e4..c0d66ee0 100644 --- a/src/main/java/electrosphere/menu/MenuGeneratorsArena.java +++ b/src/main/java/electrosphere/menu/MenuGeneratorsArena.java @@ -2,7 +2,7 @@ package electrosphere.menu; import electrosphere.auth.AuthenticationManager; import electrosphere.engine.Globals; -import electrosphere.engine.LoadingThread; +import electrosphere.engine.loadingthreads.LoadingThread; import electrosphere.net.NetUtils; import electrosphere.renderer.ui.ClickableElement; import electrosphere.renderer.ui.Element; diff --git a/src/main/java/electrosphere/menu/MenuGeneratorsTitleMenu.java b/src/main/java/electrosphere/menu/MenuGeneratorsTitleMenu.java index c5693a38..c79f4953 100644 --- a/src/main/java/electrosphere/menu/MenuGeneratorsTitleMenu.java +++ b/src/main/java/electrosphere/menu/MenuGeneratorsTitleMenu.java @@ -1,7 +1,7 @@ package electrosphere.menu; import electrosphere.engine.Globals; -import electrosphere.engine.LoadingThread; +import electrosphere.engine.loadingthreads.LoadingThread; import electrosphere.renderer.ui.ClickableElement; import electrosphere.renderer.ui.Element; import electrosphere.renderer.ui.elements.Button; diff --git a/src/main/java/electrosphere/net/client/protocol/CharacterProtocol.java b/src/main/java/electrosphere/net/client/protocol/CharacterProtocol.java index 64109ada..056425bf 100644 --- a/src/main/java/electrosphere/net/client/protocol/CharacterProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/CharacterProtocol.java @@ -1,7 +1,7 @@ package electrosphere.net.client.protocol; import electrosphere.engine.Globals; -import electrosphere.engine.LoadingThread; +import electrosphere.engine.loadingthreads.LoadingThread; import electrosphere.net.parser.net.message.CharacterMessage; import electrosphere.net.parser.net.message.TerrainMessage; diff --git a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java index 1e330d2b..22889f59 100644 --- a/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/EntityProtocol.java @@ -6,6 +6,7 @@ import org.joml.Vector3d; import electrosphere.engine.Globals; import electrosphere.engine.Main; +import electrosphere.entity.ClientEntityUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.attach.AttachUtils; @@ -32,44 +33,42 @@ public class EntityProtocol { // EntityUtils.setEntityID(newlySpawnedEntity, message.getentityID()); break; case 1: - newlySpawnedEntity = ItemUtils.spawnBasicItem(message.getentitySubtype()); + newlySpawnedEntity = ItemUtils.clientSpawnBasicItem(message.getentitySubtype()); EntityUtils.getScale(newlySpawnedEntity).set(0.005f); EntityUtils.getPosition(newlySpawnedEntity).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); - Globals.entityManager.mapIdToId(newlySpawnedEntity.getId(), message.getentityID()); + Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID()); break; } break; case SPAWNCREATURE: - if(!Globals.RUN_SERVER){ - LoggerInterface.loggerNetworking.DEBUG("Spawn Creature " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); - CreatureTemplate template = Utilities.deserialize(message.getcreatureTemplate(), CreatureTemplate.class); - newlySpawnedEntity = CreatureUtils.spawnBasicCreature(template.getCreatureType(),template); - EntityUtils.getScale(newlySpawnedEntity).set(0.005f); - EntityUtils.getPosition(newlySpawnedEntity).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); - Globals.entityManager.mapIdToId(newlySpawnedEntity.getId(), message.getentityID()); - } + LoggerInterface.loggerNetworking.DEBUG("Spawn Creature " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); + CreatureTemplate template = Utilities.deserialize(message.getcreatureTemplate(), CreatureTemplate.class); + newlySpawnedEntity = CreatureUtils.clientSpawnBasicCreature(template.getCreatureType(),template); + EntityUtils.getScale(newlySpawnedEntity).set(0.005f); + EntityUtils.getPosition(newlySpawnedEntity).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); + Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID()); break; case SPAWNITEM: if(!Globals.RUN_SERVER){ LoggerInterface.loggerNetworking.DEBUG("Spawn Item " + message.getentityID() + " at " + message.getpositionX() + " " + message.getpositionY() + " " + message.getpositionZ()); //spawn item String itemType = message.getcreatureTemplate(); - newlySpawnedEntity = ItemUtils.spawnBasicItem(itemType); + newlySpawnedEntity = ItemUtils.clientSpawnBasicItem(itemType); //position - EntityUtils.initiallyPositionEntity(newlySpawnedEntity, new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ())); - Globals.entityManager.mapIdToId(newlySpawnedEntity.getId(), message.getentityID()); + ClientEntityUtils.initiallyPositionEntity(newlySpawnedEntity, new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ())); + Globals.clientSceneWrapper.mapIdToId(newlySpawnedEntity.getId(), message.getentityID()); } break; case DESTROY: //only obey if we're not also the server if(!Globals.RUN_SERVER){ - Globals.entityManager.deregisterEntity(Globals.entityManager.getEntityFromServerId(message.getentityID())); + EntityUtils.cleanUpEntity(Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID())); } break; case MOVE: //literally just adding this to scope so I can use `` Entity target; `` again if(message.getentityID() != -1){ - Entity target = Globals.entityManager.getEntityFromServerId(message.getentityID()); + Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()); LoggerInterface.loggerNetworking.DEBUG("ID: " + message.getentityID()); if(target != null){ EntityUtils.getPosition(target).set(message.getpositionX(),message.getpositionY(),message.getpositionZ()); @@ -79,31 +78,35 @@ public class EntityProtocol { break; case SETBEHAVIORTREE: break; - case SETPROPERTY: - if(message.getpropertyType()== 0){ - Entity target = Globals.entityManager.getEntityFromServerId(message.getentityID()); - if(target != null){ - CreatureUtils.setControllerPlayerId(target, message.getpropertyValue()); - if(Globals.clientPlayer != null && message.getpropertyValue() == Globals.clientPlayer.getId()){ - Globals.clientCharacterID = message.getentityID(); - Globals.playerEntity = target; + case SETPROPERTY: { + if(Globals.clientSceneWrapper.serverToClientMapContainsId(message.getentityID())){ + if(message.getpropertyType() == 0){ + Entity target = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()); + if(target != null){ + CreatureUtils.setControllerPlayerId(target, message.getpropertyValue()); + if(Globals.clientPlayer != null && message.getpropertyValue() == Globals.clientPlayer.getId()){ + Globals.clientCharacterID = message.getentityID(); + Globals.playerEntity = target; + } } } + } else { + //TODO: bounce message } - break; + } break; case ATTACHENTITYTOENTITY: - Entity child = Globals.entityManager.getEntityFromServerId(message.getentityID()); - Entity parent = Globals.entityManager.getEntityFromServerId(message.gettargetID()); + Entity child = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()); + Entity parent = Globals.clientSceneWrapper.getEntityFromServerId(message.gettargetID()); LoggerInterface.loggerNetworking.DEBUG("Attach " + message.getentityID() + " to " + message.gettargetID() + " on bone " + message.getbone()); if(child != null && parent != null){ - AttachUtils.attachEntityToEntityAtBone(parent, child, message.getbone(), new Quaternionf()); + AttachUtils.clientAttachEntityToEntityAtBone(parent, child, message.getbone(), new Quaternionf()); } break; case MOVEUPDATE: - CreatureUtils.attachEntityMessageToMovementTree(Globals.entityManager.getEntityFromServerId(message.getentityID()),message); + CreatureUtils.clientAttachEntityMessageToMovementTree(Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()),message); break; case ATTACKUPDATE: - CreatureUtils.attachEntityMessageToAttackTree(Globals.entityManager.getEntityFromServerId(message.getentityID()),message); + CreatureUtils.attachEntityMessageToAttackTree(Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()),message); break; case KILL: break; diff --git a/src/main/java/electrosphere/net/client/protocol/InventoryProtocol.java b/src/main/java/electrosphere/net/client/protocol/InventoryProtocol.java index 8f56b50e..14ad3745 100644 --- a/src/main/java/electrosphere/net/client/protocol/InventoryProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/InventoryProtocol.java @@ -17,7 +17,7 @@ public class InventoryProtocol { LoggerInterface.loggerNetworking.DEBUG("[CLIENT] ADD ITEM TO INVENTORY " + message.getentityId()); if(Globals.playerEntity != null){ InventoryState inventoryState; - if((inventoryState = InventoryUtils.getInventoryState(Globals.playerEntity))!=null){ + if((inventoryState = InventoryUtils.clientGetInventoryState(Globals.playerEntity))!=null){ inventoryState.addNetworkMessage(message); } } @@ -25,12 +25,12 @@ public class InventoryProtocol { case SERVERCOMMANDEQUIPITEM: { LoggerInterface.loggerNetworking.DEBUG("[CLIENT] EQUIP ITEM " + message.getentityId()); //translate equipper id - Entity equipper = Globals.entityManager.getEntityFromId(Globals.entityManager.mapServerToClientId(message.getequipperId())); + Entity equipper = Globals.clientSceneWrapper.getEntityFromServerId(message.getequipperId()); //spawn in world id - Entity inWorldEntity = ItemUtils.spawnBasicItem(message.getitemTemplate()); + Entity inWorldEntity = ItemUtils.clientSpawnBasicItem(message.getitemTemplate()); if(inWorldEntity != null){ //translate id - Globals.entityManager.mapIdToId(inWorldEntity.getId(), message.getentityId()); + Globals.clientSceneWrapper.mapIdToId(inWorldEntity.getId(), message.getentityId()); //grab equip state EquipState equipState = EquipState.getEquipState(equipper); //create entity from template in message @@ -46,7 +46,7 @@ public class InventoryProtocol { LoggerInterface.loggerNetworking.DEBUG("[CLIENT] REMOVE ITEM FROM INVENTORY " + message.getentityId()); if(Globals.playerEntity != null){ InventoryState inventoryState; - if((inventoryState = InventoryUtils.getInventoryState(Globals.playerEntity))!=null){ + if((inventoryState = InventoryUtils.clientGetInventoryState(Globals.playerEntity))!=null){ inventoryState.addNetworkMessage(message); } } @@ -55,7 +55,7 @@ public class InventoryProtocol { LoggerInterface.loggerNetworking.DEBUG("[CLIENT] MOVE ITEM INVENTORY " + message.getentityId()); if(Globals.playerEntity != null){ InventoryState inventoryState; - if((inventoryState = InventoryUtils.getInventoryState(Globals.playerEntity))!=null){ + if((inventoryState = InventoryUtils.clientGetInventoryState(Globals.playerEntity))!=null){ inventoryState.addNetworkMessage(message); } } @@ -64,7 +64,7 @@ public class InventoryProtocol { LoggerInterface.loggerNetworking.DEBUG("[CLIENT] UNEQUIP ITEM " + message.getentityId()); if(Globals.playerEntity != null){ InventoryState inventoryState; - if((inventoryState = InventoryUtils.getInventoryState(Globals.playerEntity))!=null){ + if((inventoryState = InventoryUtils.clientGetInventoryState(Globals.playerEntity))!=null){ inventoryState.addNetworkMessage(message); } } diff --git a/src/main/java/electrosphere/net/client/protocol/PlayerProtocol.java b/src/main/java/electrosphere/net/client/protocol/PlayerProtocol.java index 2c52574c..792db582 100644 --- a/src/main/java/electrosphere/net/client/protocol/PlayerProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/PlayerProtocol.java @@ -1,5 +1,7 @@ package electrosphere.net.client.protocol; +import org.joml.Vector3i; + import electrosphere.engine.Globals; import electrosphere.engine.Main; import electrosphere.logger.LoggerInterface; @@ -15,7 +17,7 @@ public class PlayerProtocol { LoggerInterface.loggerNetworking.DEBUG("Player ID is " + Globals.clientPlayer.getId()); break; case SETINITIALDISCRETEPOSITION: - Globals.clientPlayerData.setWorldPosition(message.getinitialDiscretePositionX(), message.getinitialDiscretePositionY()); + Globals.clientPlayerData.setWorldPos(new Vector3i(message.getinitialDiscretePositionX(), message.getinitialDiscretePositionY(), message.getinitialDiscretePositionZ())); break; } } diff --git a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java index 0c33ec13..d6aec938 100644 --- a/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/client/protocol/TerrainProtocol.java @@ -22,13 +22,14 @@ public class TerrainProtocol { message.getrandomDampener(), message.getworldSizeDiscrete() ); + Globals.clientTerrainManager.setClientWorldData(Globals.clientWorldData); Globals.clientConnection.getClientProtocol().setHasReceivedWorld(true); break; case MACROVALUE: Globals.clientTerrainManager.attachTerrainMessage(message); break; case SPAWNPOSITION: - Globals.spawnPoint.set(message.getrealLocationX(),0.25,message.getrealLocationY()); + Globals.spawnPoint.set(message.getrealLocationX(),0.25,message.getrealLocationZ()); break; case CHUNKLOADSTART: Globals.clientTerrainManager.attachTerrainMessage(message); diff --git a/src/main/java/electrosphere/net/parser/net/message/PlayerMessage.java b/src/main/java/electrosphere/net/parser/net/message/PlayerMessage.java index 3ed31dad..60494bff 100644 --- a/src/main/java/electrosphere/net/parser/net/message/PlayerMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/PlayerMessage.java @@ -15,6 +15,7 @@ public class PlayerMessage extends NetworkMessage { int playerID; int initialDiscretePositionX; int initialDiscretePositionY; + int initialDiscretePositionZ; PlayerMessage(PlayerMessageType messageType){ this.type = MessageType.PLAYER_MESSAGE; @@ -49,6 +50,14 @@ public class PlayerMessage extends NetworkMessage { this.initialDiscretePositionY = initialDiscretePositionY; } + public int getinitialDiscretePositionZ() { + return initialDiscretePositionZ; + } + + public void setinitialDiscretePositionZ(int initialDiscretePositionZ) { + this.initialDiscretePositionZ = initialDiscretePositionZ; + } + static void stripPacketHeader(List byteStream){ byteStream.remove(0); byteStream.remove(0); @@ -91,13 +100,15 @@ public class PlayerMessage extends NetworkMessage { stripPacketHeader(byteStream); rVal.setinitialDiscretePositionX(ByteStreamUtils.popIntFromByteQueue(byteStream)); rVal.setinitialDiscretePositionY(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setinitialDiscretePositionZ(ByteStreamUtils.popIntFromByteQueue(byteStream)); return rVal; } - public static PlayerMessage constructSetInitialDiscretePositionMessage(int initialDiscretePositionX,int initialDiscretePositionY){ + public static PlayerMessage constructSetInitialDiscretePositionMessage(int initialDiscretePositionX,int initialDiscretePositionY,int initialDiscretePositionZ){ PlayerMessage rVal = new PlayerMessage(PlayerMessageType.SETINITIALDISCRETEPOSITION); rVal.setinitialDiscretePositionX(initialDiscretePositionX); rVal.setinitialDiscretePositionY(initialDiscretePositionY); + rVal.setinitialDiscretePositionZ(initialDiscretePositionZ); rVal.serialize(); return rVal; } @@ -119,7 +130,7 @@ public class PlayerMessage extends NetworkMessage { } break; case SETINITIALDISCRETEPOSITION: - rawBytes = new byte[2+4+4]; + rawBytes = new byte[2+4+4+4]; //message header rawBytes[0] = TypeBytes.MESSAGE_TYPE_PLAYER; //entity messaage header @@ -132,6 +143,10 @@ public class PlayerMessage extends NetworkMessage { for(int i = 0; i < 4; i++){ rawBytes[6+i] = intValues[i]; } + intValues = ByteStreamUtils.serializeIntToBytes(initialDiscretePositionZ); + for(int i = 0; i < 4; i++){ + rawBytes[10+i] = intValues[i]; + } break; } serialized = true; diff --git a/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java b/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java index ea4ba981..ea0ef35f 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java +++ b/src/main/java/electrosphere/net/parser/net/message/TerrainMessage.java @@ -27,11 +27,14 @@ public class TerrainMessage extends NetworkMessage { int worldMaxY; int worldX; int worldY; + int worldZ; float value; int locationX; int locationY; + int locationZ; double realLocationX; double realLocationY; + double realLocationZ; float macroValue00; float macroValue01; float macroValue02; @@ -164,6 +167,14 @@ public class TerrainMessage extends NetworkMessage { this.worldY = worldY; } + public int getworldZ() { + return worldZ; + } + + public void setworldZ(int worldZ) { + this.worldZ = worldZ; + } + public float getvalue() { return value; } @@ -188,6 +199,14 @@ public class TerrainMessage extends NetworkMessage { this.locationY = locationY; } + public int getlocationZ() { + return locationZ; + } + + public void setlocationZ(int locationZ) { + this.locationZ = locationZ; + } + public double getrealLocationX() { return realLocationX; } @@ -204,6 +223,14 @@ public class TerrainMessage extends NetworkMessage { this.realLocationY = realLocationY; } + public double getrealLocationZ() { + return realLocationZ; + } + + public void setrealLocationZ(double realLocationZ) { + this.realLocationZ = realLocationZ; + } + public float getmacroValue00() { return macroValue00; } @@ -722,13 +749,15 @@ public class TerrainMessage extends NetworkMessage { stripPacketHeader(byteStream); rVal.setlocationX(ByteStreamUtils.popIntFromByteQueue(byteStream)); rVal.setlocationY(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setlocationZ(ByteStreamUtils.popIntFromByteQueue(byteStream)); return rVal; } - public static TerrainMessage constructUpdateMessage(int locationX,int locationY){ + public static TerrainMessage constructUpdateMessage(int locationX,int locationY,int locationZ){ TerrainMessage rVal = new TerrainMessage(TerrainMessageType.UPDATE); rVal.setlocationX(locationX); rVal.setlocationY(locationY); + rVal.setlocationZ(locationZ); rVal.serialize(); return rVal; } @@ -873,18 +902,22 @@ public class TerrainMessage extends NetworkMessage { rVal.setvalue(ByteStreamUtils.popFloatFromByteQueue(byteStream)); rVal.setworldX(ByteStreamUtils.popIntFromByteQueue(byteStream)); rVal.setworldY(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setworldZ(ByteStreamUtils.popIntFromByteQueue(byteStream)); rVal.setlocationX(ByteStreamUtils.popIntFromByteQueue(byteStream)); rVal.setlocationY(ByteStreamUtils.popIntFromByteQueue(byteStream)); + rVal.setlocationZ(ByteStreamUtils.popIntFromByteQueue(byteStream)); return rVal; } - public static TerrainMessage constructheightMapModificationMessage(float value,int worldX,int worldY,int locationX,int locationY){ + public static TerrainMessage constructheightMapModificationMessage(float value,int worldX,int worldY,int worldZ,int locationX,int locationY,int locationZ){ TerrainMessage rVal = new TerrainMessage(TerrainMessageType.HEIGHTMAPMODIFICATION); rVal.setvalue(value); rVal.setworldX(worldX); rVal.setworldY(worldY); + rVal.setworldZ(worldZ); rVal.setlocationX(locationX); rVal.setlocationY(locationY); + rVal.setlocationZ(locationZ); rVal.serialize(); return rVal; } @@ -894,13 +927,15 @@ public class TerrainMessage extends NetworkMessage { stripPacketHeader(byteStream); rVal.setrealLocationX(ByteStreamUtils.popDoubleFromByteQueue(byteStream)); rVal.setrealLocationY(ByteStreamUtils.popDoubleFromByteQueue(byteStream)); + rVal.setrealLocationZ(ByteStreamUtils.popDoubleFromByteQueue(byteStream)); return rVal; } - public static TerrainMessage constructSpawnPositionMessage(double realLocationX,double realLocationY){ + public static TerrainMessage constructSpawnPositionMessage(double realLocationX,double realLocationY,double realLocationZ){ TerrainMessage rVal = new TerrainMessage(TerrainMessageType.SPAWNPOSITION); rVal.setrealLocationX(realLocationX); rVal.setrealLocationY(realLocationY); + rVal.setrealLocationZ(realLocationZ); rVal.serialize(); return rVal; } @@ -967,7 +1002,7 @@ public class TerrainMessage extends NetworkMessage { } break; case UPDATE: - rawBytes = new byte[2+4+4]; + rawBytes = new byte[2+4+4+4]; //message header rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN; //entity messaage header @@ -980,6 +1015,10 @@ public class TerrainMessage extends NetworkMessage { for(int i = 0; i < 4; i++){ rawBytes[6+i] = intValues[i]; } + intValues = ByteStreamUtils.serializeIntToBytes(locationZ); + for(int i = 0; i < 4; i++){ + rawBytes[10+i] = intValues[i]; + } break; case CHUNKLOADSTART: rawBytes = new byte[2+4+4+4]; @@ -1190,7 +1229,7 @@ public class TerrainMessage extends NetworkMessage { } break; case HEIGHTMAPMODIFICATION: - rawBytes = new byte[2+4+4+4+4+4]; + rawBytes = new byte[2+4+4+4+4+4+4+4]; //message header rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN; //entity messaage header @@ -1206,17 +1245,25 @@ public class TerrainMessage extends NetworkMessage { for(int i = 0; i < 4; i++){ rawBytes[10+i] = intValues[i]; } - intValues = ByteStreamUtils.serializeIntToBytes(locationX); + intValues = ByteStreamUtils.serializeIntToBytes(worldZ); for(int i = 0; i < 4; i++){ rawBytes[14+i] = intValues[i]; } - intValues = ByteStreamUtils.serializeIntToBytes(locationY); + intValues = ByteStreamUtils.serializeIntToBytes(locationX); for(int i = 0; i < 4; i++){ rawBytes[18+i] = intValues[i]; } + intValues = ByteStreamUtils.serializeIntToBytes(locationY); + for(int i = 0; i < 4; i++){ + rawBytes[22+i] = intValues[i]; + } + intValues = ByteStreamUtils.serializeIntToBytes(locationZ); + for(int i = 0; i < 4; i++){ + rawBytes[26+i] = intValues[i]; + } break; case SPAWNPOSITION: - rawBytes = new byte[2+8+8]; + rawBytes = new byte[2+8+8+8]; //message header rawBytes[0] = TypeBytes.MESSAGE_TYPE_TERRAIN; //entity messaage header @@ -1229,6 +1276,10 @@ public class TerrainMessage extends NetworkMessage { for(int i = 0; i < 8; i++){ rawBytes[10+i] = intValues[i]; } + intValues = ByteStreamUtils.serializeDoubleToBytes(realLocationZ); + for(int i = 0; i < 8; i++){ + rawBytes[18+i] = intValues[i]; + } break; } serialized = true; diff --git a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java index 2012e28f..ef19c5d6 100644 --- a/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java +++ b/src/main/java/electrosphere/net/parser/net/message/TypeBytes.java @@ -73,7 +73,7 @@ Message categories Player packet sizes */ public static final byte PLAYER_MESSAGE_TYPE_SET_ID_SIZE = 6; - public static final byte PLAYER_MESSAGE_TYPE_SETINITIALDISCRETEPOSITION_SIZE = 10; + public static final byte PLAYER_MESSAGE_TYPE_SETINITIALDISCRETEPOSITION_SIZE = 14; /* Terrain subcategories */ @@ -91,11 +91,11 @@ Message categories public static final byte TERRAIN_MESSAGE_TYPE_REQUESTMETADATA_SIZE = 2; public static final byte TERRAIN_MESSAGE_TYPE_RESPONSEMETADATA_SIZE = 30; public static final byte TERRAIN_MESSAGE_TYPE_REQUESTCHUNK_SIZE = 10; - public static final byte TERRAIN_MESSAGE_TYPE_UPDATE_SIZE = 10; + public static final byte TERRAIN_MESSAGE_TYPE_UPDATE_SIZE = 14; public static final byte TERRAIN_MESSAGE_TYPE_CHUNKLOADSTART_SIZE = 14; public static final short TERRAIN_MESSAGE_TYPE_MACROVALUE_SIZE = 310; - public static final byte TERRAIN_MESSAGE_TYPE_HEIGHTMAPMODIFICATION_SIZE = 22; - public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION_SIZE = 18; + public static final byte TERRAIN_MESSAGE_TYPE_HEIGHTMAPMODIFICATION_SIZE = 30; + public static final byte TERRAIN_MESSAGE_TYPE_SPAWNPOSITION_SIZE = 26; /* Server subcategories */ diff --git a/src/main/java/electrosphere/net/server/ServerConnectionHandler.java b/src/main/java/electrosphere/net/server/ServerConnectionHandler.java index 52dc0cb6..914c0115 100644 --- a/src/main/java/electrosphere/net/server/ServerConnectionHandler.java +++ b/src/main/java/electrosphere/net/server/ServerConnectionHandler.java @@ -262,38 +262,7 @@ public class ServerConnectionHandler implements Runnable { } public void addMessagetoOutgoingQueue(NetworkMessage message){ - switch(message.getType()){ - case ENTITY_MESSAGE: - switch(((EntityMessage)message).getMessageSubtype()){ - case MOVEUPDATE: - //we don't want this to fire if it's the server client because other people will keep running indefinitely - //as the server broadcasts to itself that they're moving - case ATTACKUPDATE: - //we don't want this to fire if it's the server client because other people will keep running indefinitely - //as the server broadcasts to itself that they're moving - case SPAWNCREATURE: - if(isServerClient()){ - //basically don't send the message if this is the player that is also hosting the game - } else { - networkParser.addOutgoingMessage(message); - } - break; - default: - networkParser.addOutgoingMessage(message); - break; - } - break; - case INVENTORY_MESSAGE: - if(isServerClient()){ - //basically don't send the message if this is the player that is also hosting the game - } else { - networkParser.addOutgoingMessage(message); - } - break; - default: - networkParser.addOutgoingMessage(message); - break; - } + networkParser.addOutgoingMessage(message); } boolean isConnectionPlayerEntity(int id){ @@ -338,9 +307,9 @@ public class ServerConnectionHandler implements Runnable { Entity playerEntity = playerObject.getPlayerEntity(); Vector3d position = EntityUtils.getPosition(playerEntity); //deregister entity - Globals.entityManager.deregisterEntity(playerObject.getPlayerEntity()); - //tell all clients to destroy the entity - Globals.dataCellManager.getDataCellAtPoint(position).broadcastNetworkMessage(EntityMessage.constructDestroyMessage(playerEntity.getId())); + EntityUtils.cleanUpEntity(playerObject.getPlayerEntity()); + //TODO: tell all clients to destroy the entity + EntityUtils.cleanUpEntity(playerEntity); } } diff --git a/src/main/java/electrosphere/net/server/player/Player.java b/src/main/java/electrosphere/net/server/player/Player.java index 0f0a5287..3e92ff9e 100644 --- a/src/main/java/electrosphere/net/server/player/Player.java +++ b/src/main/java/electrosphere/net/server/player/Player.java @@ -7,6 +7,8 @@ import electrosphere.net.server.ServerConnectionHandler; import java.util.concurrent.Semaphore; +import org.joml.Vector3i; + /** * * @author satellite @@ -17,8 +19,7 @@ public class Player { int id; static Semaphore idIncrementerLock = new Semaphore(1); static int idIncrementer = 0; - int worldX; - int worldY; + Vector3i worldPos; int simulationRadius = 3; Entity playerEntity; @@ -45,20 +46,12 @@ public class Player { connectionHandler.addMessagetoOutgoingQueue(message); } - public int getWorldX() { - return worldX; + public Vector3i getWorldPos() { + return worldPos; } - public int getWorldY() { - return worldY; - } - - public void setWorldX(int worldX) { - this.worldX = worldX; - } - - public void setWorldY(int worldY) { - this.worldY = worldY; + public void setWorldPos(Vector3i worldPos) { + this.worldPos = worldPos; } public int getSimulationRadius() { diff --git a/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java b/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java index fcd7ea32..d7168dae 100644 --- a/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/CharacterProtocol.java @@ -2,11 +2,13 @@ package electrosphere.net.server.protocol; import org.joml.Vector3d; import org.joml.Vector3f; +import org.joml.Vector3i; import electrosphere.engine.Globals; import electrosphere.engine.Main; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; +import electrosphere.entity.ServerEntityUtils; import electrosphere.entity.state.ironsight.IronSightTree; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.creature.CreatureTemplate; @@ -16,6 +18,7 @@ import electrosphere.net.parser.net.message.PlayerMessage; import electrosphere.net.parser.net.message.TerrainMessage; import electrosphere.net.server.ServerConnectionHandler; import electrosphere.net.server.player.Player; +import electrosphere.server.datacell.Realm; import electrosphere.util.Utilities; public class CharacterProtocol { @@ -52,18 +55,20 @@ public class CharacterProtocol { CreatureTemplate template = connectionHandler.getCurrentCreatureTemplate(); String raceName = template.getCreatureType(); //spawn player in world - Entity newPlayerEntity = CreatureUtils.spawnBasicCreature(raceName,template); + Realm realm = Globals.realmManager.getRealms().iterator().next(); + Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(Globals.spawnPoint.x,Globals.spawnPoint.y,Globals.spawnPoint.z),raceName,template); int playerCharacterId = newPlayerEntity.getId(); connectionHandler.setPlayerCharacterId(playerCharacterId); - EntityUtils.initiallyPositionEntity(newPlayerEntity, new Vector3d(Globals.spawnPoint.x,Globals.spawnPoint.y,Globals.spawnPoint.z)); CreatureUtils.setControllerPlayerId(newPlayerEntity, connectionHandler.getPlayerId()); //attach player object to player character playerObject.setPlayerEntity(newPlayerEntity); - playerObject.setWorldX(Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x)); - playerObject.setWorldY(Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z)); + playerObject.setWorldPos(new Vector3i( + Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x), + Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.y), + Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z) + )); // System.out.println(EntityUtils.getRotation(newPlayerCharacter).set(0,1,0,1).normalize()); - Globals.dataCellManager.addPlayerToGroundCells(playerObject); - Globals.dataCellManager.movePlayerGroundCells(playerObject, Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x), Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z)); + realm.getDataCellManager().addPlayerToRealm(playerObject); // IronSightTree.attachIronSightTree(newPlayerEntity); // //spawn player sword // Entity sword = ItemUtils.spawnBasicItem("Katana"); @@ -77,15 +82,16 @@ public class CharacterProtocol { static void spawnClientEntity(ServerConnectionHandler connectionHandler){ spawnPlayerCharacter(connectionHandler); //set client initial discrete position - // connectionHandler.addMessagetoOutgoingQueue( - // PlayerMessage.constructSetInitialDiscretePositionMessage( - // Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x), - // Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z) - // ) - // ); + connectionHandler.addMessagetoOutgoingQueue( + PlayerMessage.constructSetInitialDiscretePositionMessage( + Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x), + Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.y), + Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z) + ) + ); //send spawn point connectionHandler.addMessagetoOutgoingQueue( - TerrainMessage.constructSpawnPositionMessage(Globals.spawnPoint.x, Globals.spawnPoint.z) + TerrainMessage.constructSpawnPositionMessage(Globals.spawnPoint.x, Globals.spawnPoint.y, Globals.spawnPoint.z) ); //tell them what player stats they are // connectionHandler.addMessagetoOutgoingQueue(PlayerMessage.constructSet_IDMessage(connectionHandler.getPlayerCharacterId())); diff --git a/src/main/java/electrosphere/net/server/protocol/EntityProtocol.java b/src/main/java/electrosphere/net/server/protocol/EntityProtocol.java index dbfa4943..f2426b86 100644 --- a/src/main/java/electrosphere/net/server/protocol/EntityProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/EntityProtocol.java @@ -11,6 +11,7 @@ import electrosphere.logger.LoggerInterface; import electrosphere.net.NetUtils; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.server.ServerConnectionHandler; +import electrosphere.server.datacell.utils.EntityLookupUtils; public class EntityProtocol { @@ -18,21 +19,21 @@ public class EntityProtocol { Entity targetEntity; switch(message.getMessageSubtype()){ case MOVE: - targetEntity = Globals.entityManager.getEntityFromId(message.getentityID()); + targetEntity = EntityLookupUtils.getEntityById(message.getentityID()); if(targetEntity != null){ - CreatureUtils.attachEntityMessageToMovementTree(targetEntity,message); + CreatureUtils.serverAttachEntityMessageToMovementTree(targetEntity,message); } break; case SETBEHAVIORTREE: break; case MOVEUPDATE: - targetEntity = Globals.entityManager.getEntityFromId(message.getentityID()); + targetEntity = EntityLookupUtils.getEntityById(message.getentityID()); if(targetEntity != null){ - CreatureUtils.attachEntityMessageToMovementTree(targetEntity,message); + CreatureUtils.serverAttachEntityMessageToMovementTree(targetEntity,message); } break; case ATTACKUPDATE: - targetEntity = Globals.entityManager.getEntityFromId(message.getentityID()); + targetEntity = EntityLookupUtils.getEntityById(message.getentityID()); if(targetEntity != null){ CreatureUtils.attachEntityMessageToAttackTree(targetEntity,message); } diff --git a/src/main/java/electrosphere/net/server/protocol/InventoryProtocol.java b/src/main/java/electrosphere/net/server/protocol/InventoryProtocol.java index b7de2dc5..d7a9591f 100644 --- a/src/main/java/electrosphere/net/server/protocol/InventoryProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/InventoryProtocol.java @@ -10,6 +10,7 @@ import electrosphere.game.data.creature.type.equip.EquipPoint; import electrosphere.logger.LoggerInterface; import electrosphere.net.parser.net.message.InventoryMessage; import electrosphere.net.server.ServerConnectionHandler; +import electrosphere.server.datacell.utils.EntityLookupUtils; public class InventoryProtocol { @@ -22,30 +23,30 @@ public class InventoryProtocol { switch(message.getMessageSubtype()){ case ADDITEMTOINVENTORY: LoggerInterface.loggerNetworking.DEBUG("[SERVER] ADD ITEM TO INVENTORY " + message.getentityId()); - target = Globals.entityManager.getEntityFromId(connectionHandler.getPlayerCharacterId()); + target = EntityLookupUtils.getEntityById(connectionHandler.getPlayerCharacterId()); if(InventoryUtils.hasNaturalInventory(target)){ - InventoryUtils.getInventoryState(target).addNetworkMessage(message); + InventoryUtils.serverGetInventoryState(target).addNetworkMessage(message); } break; case REMOVEITEMFROMINVENTORY: LoggerInterface.loggerNetworking.DEBUG("[SERVER] REMOVE ITEM FROM INVENTORY " + message.getentityId()); - target = Globals.entityManager.getEntityFromId(connectionHandler.getPlayerCharacterId()); + target = EntityLookupUtils.getEntityById(connectionHandler.getPlayerCharacterId()); if(InventoryUtils.hasNaturalInventory(target)){ - InventoryUtils.getInventoryState(target).addNetworkMessage(message); + InventoryUtils.serverGetInventoryState(target).addNetworkMessage(message); } break; case CLIENTREQUESTEQUIPITEM: LoggerInterface.loggerNetworking.DEBUG("[SERVER] REQUEST EQUIP ITEM " + message.getentityId()); - target = Globals.entityManager.getEntityFromId(connectionHandler.getPlayerCharacterId()); + target = EntityLookupUtils.getEntityById(connectionHandler.getPlayerCharacterId()); if(InventoryUtils.hasNaturalInventory(target)){ - InventoryUtils.getInventoryState(target).addNetworkMessage(message); + InventoryUtils.serverGetInventoryState(target).addNetworkMessage(message); } break; case CLIENTREQUESTUNEQUIPITEM: LoggerInterface.loggerNetworking.DEBUG("[SERVER] REQUEST UNEQUIP ITEM " + message.getentityId()); - target = Globals.entityManager.getEntityFromId(connectionHandler.getPlayerCharacterId()); + target = EntityLookupUtils.getEntityById(connectionHandler.getPlayerCharacterId()); if(InventoryUtils.hasNaturalInventory(target)){ - InventoryUtils.getInventoryState(target).addNetworkMessage(message); + InventoryUtils.serverGetInventoryState(target).addNetworkMessage(message); } break; case SERVERCOMMANDUNEQUIPITEM: diff --git a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java index 04be59bc..2ec16918 100644 --- a/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java +++ b/src/main/java/electrosphere/net/server/protocol/TerrainProtocol.java @@ -134,8 +134,10 @@ public class TerrainProtocol { TerrainMessage.constructheightMapModificationMessage( modification.getValue(), modification.getWorldX(), + 0, modification.getWorldY(), modification.getLocationX(), + 0, modification.getLocationY() ) ); diff --git a/src/main/java/electrosphere/renderer/RenderingEngine.java b/src/main/java/electrosphere/renderer/RenderingEngine.java index 075252d8..e528a6f2 100644 --- a/src/main/java/electrosphere/renderer/RenderingEngine.java +++ b/src/main/java/electrosphere/renderer/RenderingEngine.java @@ -569,7 +569,7 @@ public class RenderingEngine { // Vector3f cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); modelTransformMatrix = new Matrix4f(); - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.DRAWABLE)){ + for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if( (boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && @@ -647,7 +647,7 @@ public class RenderingEngine { // Vector3f cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); modelTransformMatrix = new Matrix4f(); - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.DRAWABLE)){ + for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if( (boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && @@ -700,7 +700,7 @@ public class RenderingEngine { // - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.DRAWABLE)){ + for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if( (boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && @@ -773,7 +773,7 @@ public class RenderingEngine { // Vector3f cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); modelTransformMatrix = new Matrix4f(); - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.DRAWABLE)){ + for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if( (boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && @@ -824,7 +824,7 @@ public class RenderingEngine { Matrix4f modelTransformMatrix = new Matrix4f(); if(Globals.userSettings.graphicsDebugDrawCollisionSpheres()){ - for(Entity currentHitbox : Globals.hitboxManager.getAllHitboxes()){ + for(Entity currentHitbox : Globals.clientHitboxManager.getAllHitboxes()){ if((boolean)currentHitbox.getData(EntityDataStrings.DATA_STRING_DRAW)){ Model hitboxModel; HitboxData data = HitboxUtils.getHitboxData(currentHitbox); @@ -871,7 +871,7 @@ public class RenderingEngine { if(Globals.userSettings.graphicsDebugDrawPhysicsObjects()){ Model physicsGraphicsModel; - for(Entity physicsEntity : Globals.collisionEngine.getDynamicPhysicsEntities()){ + for(Entity physicsEntity : Globals.clientSceneWrapper.getCollisionEngine().getDynamicPhysicsEntities()){ if((boolean)physicsEntity.getData(EntityDataStrings.DATA_STRING_DRAW)){ CollidableTemplate template = (CollidableTemplate)physicsEntity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE); switch(template.getType()){ @@ -908,7 +908,7 @@ public class RenderingEngine { } } } - for(Entity physicsEntity : Globals.collisionEngine.getStructurePhysicsEntities()){ + for(Entity physicsEntity : Globals.clientSceneWrapper.getCollisionEngine().getStructurePhysicsEntities()){ if((boolean)physicsEntity.getData(EntityDataStrings.DATA_STRING_DRAW)){ if(physicsEntity.containsKey(EntityDataStrings.COLLISION_ENTITY_TYPE_PLANE)){ if((physicsGraphicsModel = Globals.assetManager.fetchModel("Models/unitplane.fbx")) != null){ @@ -1017,7 +1017,7 @@ public class RenderingEngine { Vector3f cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); modelTransformMatrix = new Matrix4f(); - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.DRAWABLE)){ + for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if( (boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && @@ -1272,7 +1272,7 @@ public class RenderingEngine { // D R A W A L L E N T I T I E S // Vector3f cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.DRAWABLE)){ + for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if( (boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && @@ -1310,7 +1310,7 @@ public class RenderingEngine { //Draw front faces of all non-volumetrics // cameraPos = CameraEntityUtils.getCameraCenter(Globals.playerCamera); - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.DRAWABLE)){ + for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if( (boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && @@ -1359,7 +1359,7 @@ public class RenderingEngine { // // D R A W A L L E N T I T I E S // - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.DRAWABLE)){ + for(Entity currentEntity : Globals.clientScene.getEntitiesWithTag(EntityTags.DRAWABLE)){ Vector3d position = EntityUtils.getPosition(currentEntity); if( (boolean)currentEntity.getData(EntityDataStrings.DATA_STRING_DRAW) && diff --git a/src/main/java/electrosphere/renderer/light/LightEntityUtils.java b/src/main/java/electrosphere/renderer/light/LightEntityUtils.java index fc433f41..85fd1429 100644 --- a/src/main/java/electrosphere/renderer/light/LightEntityUtils.java +++ b/src/main/java/electrosphere/renderer/light/LightEntityUtils.java @@ -2,6 +2,7 @@ package electrosphere.renderer.light; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; @@ -15,9 +16,8 @@ import org.joml.Vector3f; public class LightEntityUtils { public static Entity createDirectionalLight(Vector3f position, Vector3f ambient, Vector3f diffuse, Vector3f specular){ - Entity rVal = new Entity(); - Globals.entityManager.registerEntity(rVal); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.LIGHT); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.LIGHT); rVal.putData(EntityDataStrings.DATA_STRING_LIGHT_TYPE, EntityDataStrings.DATA_STRING_LIGHT_TYPE_DIRECTIONAL); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(position.x,position.y,position.z)); rVal.putData(EntityDataStrings.DATA_STRING_LIGHT_AMBIENT, ambient); @@ -27,9 +27,8 @@ public class LightEntityUtils { } public static Entity createPointLight(Vector3f position, Vector3f ambient, Vector3f diffuse, Vector3f specular, float constant, float linear, float quadratic){ - Entity rVal = new Entity(); - Globals.entityManager.registerEntity(rVal); - Globals.entityManager.registerEntityToTag(rVal, EntityTags.LIGHT); + Entity rVal = EntityCreationUtils.createClientSpatialEntity(); + Globals.clientScene.registerEntityToTag(rVal, EntityTags.LIGHT); rVal.putData(EntityDataStrings.DATA_STRING_LIGHT_TYPE, EntityDataStrings.DATA_STRING_LIGHT_TYPE_POINT); rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(position.x,position.y,position.z)); rVal.putData(EntityDataStrings.DATA_STRING_LIGHT_AMBIENT, ambient); diff --git a/src/main/java/electrosphere/server/ai/creature/MillAbout.java b/src/main/java/electrosphere/server/ai/creature/MillAbout.java index 1a03efb5..d1783bdb 100644 --- a/src/main/java/electrosphere/server/ai/creature/MillAbout.java +++ b/src/main/java/electrosphere/server/ai/creature/MillAbout.java @@ -79,12 +79,12 @@ public class MillAbout extends AI { if(moveTargetPosition.distance(position) > 0.4){ Vector3d moveVector = new Vector3d(moveTargetPosition).sub(position).normalize(); CreatureUtils.setFacingVector(character, new Vector3d((float)moveVector.x,(float)moveVector.y,(float)moveVector.z)); - GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.getEntityMovementTree(character); + GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.serverGetEntityMovementTree(character); if(characterMoveTree.getState()==GroundMovementTree.MovementTreeState.IDLE || characterMoveTree.getState()==GroundMovementTree.MovementTreeState.SLOWDOWN){ characterMoveTree.start(MovementRelativeFacing.FORWARD); } } else { - GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.getEntityMovementTree(character); + GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.serverGetEntityMovementTree(character); characterMoveTree.slowdown(); // System.out.println("Made it to destination"); moveToTarget = false; diff --git a/src/main/java/electrosphere/server/ai/creature/MindlessAttacker.java b/src/main/java/electrosphere/server/ai/creature/MindlessAttacker.java index 4a308e5b..0d12b162 100644 --- a/src/main/java/electrosphere/server/ai/creature/MindlessAttacker.java +++ b/src/main/java/electrosphere/server/ai/creature/MindlessAttacker.java @@ -6,10 +6,13 @@ import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.attack.AttackTree; +import electrosphere.entity.state.attack.ServerAttackTree; import electrosphere.entity.state.movement.GroundMovementTree; import electrosphere.entity.state.movement.GroundMovementTree.MovementRelativeFacing; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.server.ai.AI; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.utils.DataCellSearchUtils; import org.joml.Vector3d; import org.joml.Vector3f; @@ -61,7 +64,7 @@ public class MindlessAttacker extends AI{ void attack(){ if(attackCooldown == 0){ attackCooldown = attackCooldownMax; - AttackTree attackTree = CreatureUtils.getAttackTree(character); + ServerAttackTree attackTree = CreatureUtils.serverGetAttackTree(character); attackTree.start(); } else { attackCooldown--; @@ -73,7 +76,7 @@ public class MindlessAttacker extends AI{ Vector3d characterPosition = EntityUtils.getPosition(character); Vector3d moveVector = new Vector3d(targetPosition).sub(characterPosition).normalize(); CreatureUtils.setFacingVector(character, new Vector3d((float)moveVector.x,(float)moveVector.y,(float)moveVector.z)); - GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.getEntityMovementTree(character); + GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.serverGetEntityMovementTree(character); if(characterMoveTree.getState()==GroundMovementTree.MovementTreeState.IDLE || characterMoveTree.getState()==GroundMovementTree.MovementTreeState.SLOWDOWN){ characterMoveTree.start(MovementRelativeFacing.FORWARD); } @@ -102,7 +105,8 @@ public class MindlessAttacker extends AI{ void searchForTarget(){ Vector3d position = EntityUtils.getPosition(character); - for(Entity current : Globals.entityManager.getEntitiesWithTag(EntityTags.LIFE_STATE)){ + Realm realm = Globals.realmManager.getEntityRealm(character); + for(Entity current : DataCellSearchUtils.getEntitiesWithTagAroundLocation(realm,position,EntityTags.LIFE_STATE)){ if(current != character){ Vector3d potentialTargetPosition = EntityUtils.getPosition(current); if(position.distance(potentialTargetPosition) < aggroRange){ diff --git a/src/main/java/electrosphere/server/ai/creature/OpportunisticAttacker.java b/src/main/java/electrosphere/server/ai/creature/OpportunisticAttacker.java index de0382fe..35c1d97f 100644 --- a/src/main/java/electrosphere/server/ai/creature/OpportunisticAttacker.java +++ b/src/main/java/electrosphere/server/ai/creature/OpportunisticAttacker.java @@ -6,12 +6,15 @@ import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.attack.AttackTree; +import electrosphere.entity.state.attack.ServerAttackTree; import electrosphere.entity.state.equip.EquipState; import electrosphere.entity.state.movement.GroundMovementTree; import electrosphere.entity.state.movement.GroundMovementTree.MovementRelativeFacing; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.item.ItemUtils; import electrosphere.server.ai.AI; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.utils.DataCellSearchUtils; import org.joml.Vector3f; @@ -152,7 +155,7 @@ public class OpportunisticAttacker extends AI { void attack(){ if(attackCooldown == 0){ attackCooldown = attackCooldownMax; - AttackTree attackTree = CreatureUtils.getAttackTree(character); + ServerAttackTree attackTree = CreatureUtils.serverGetAttackTree(character); attackTree.start(); } else { attackCooldown--; @@ -164,7 +167,7 @@ public class OpportunisticAttacker extends AI { Vector3d characterPosition = EntityUtils.getPosition(character); Vector3d moveVector = new Vector3d(targetPosition).sub(characterPosition).normalize(); CreatureUtils.setFacingVector(character, new Vector3d((float)moveVector.x,(float)moveVector.y,(float)moveVector.z)); - GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.getEntityMovementTree(character); + GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.serverGetEntityMovementTree(character); if(characterMoveTree.getState()==GroundMovementTree.MovementTreeState.IDLE || characterMoveTree.getState()==GroundMovementTree.MovementTreeState.SLOWDOWN){ characterMoveTree.start(MovementRelativeFacing.FORWARD); } @@ -193,7 +196,8 @@ public class OpportunisticAttacker extends AI { void searchForTarget(){ Vector3d position = EntityUtils.getPosition(character); - for(Entity current : Globals.entityManager.getEntitiesWithTag(EntityTags.LIFE_STATE)){ + Realm realm = Globals.realmManager.getEntityRealm(character); + for(Entity current : DataCellSearchUtils.getEntitiesWithTagAroundLocation(realm,position,EntityTags.LIFE_STATE)){ if(current != character){ Vector3d potentialTargetPosition = EntityUtils.getPosition(current); if(position.distance(potentialTargetPosition) < aggroRange){ @@ -220,7 +224,8 @@ public class OpportunisticAttacker extends AI { boolean weaponInRange(){ boolean rVal = false; Vector3d position = EntityUtils.getPosition(character); - for(Entity current : Globals.entityManager.getEntitiesWithTag(EntityTags.ITEM)){ + Realm realm = Globals.realmManager.getEntityRealm(character); + for(Entity current : DataCellSearchUtils.getEntitiesWithTagAroundLocation(realm,position,EntityTags.ITEM)){ if(current != character && ItemUtils.isItem(current) && ItemUtils.isWeapon(current)){ Vector3d potentialTargetPosition = EntityUtils.getPosition(current); if(position.distance(potentialTargetPosition) < weaponSeekRange){ diff --git a/src/main/java/electrosphere/server/ai/creature/adventurer/SeekTown.java b/src/main/java/electrosphere/server/ai/creature/adventurer/SeekTown.java index 3e0da0ef..666eea0c 100644 --- a/src/main/java/electrosphere/server/ai/creature/adventurer/SeekTown.java +++ b/src/main/java/electrosphere/server/ai/creature/adventurer/SeekTown.java @@ -49,7 +49,7 @@ public class SeekTown extends AI { Vector3d characterPosition = EntityUtils.getPosition(character); Vector3d moveVector = new Vector3d(targetPosition).sub(characterPosition).normalize(); CreatureUtils.setFacingVector(character, new Vector3d((float)moveVector.x,(float)moveVector.y,(float)moveVector.z)); - GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.getEntityMovementTree(character); + GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.serverGetEntityMovementTree(character); if(characterMoveTree.getState()==GroundMovementTree.MovementTreeState.IDLE || characterMoveTree.getState()==GroundMovementTree.MovementTreeState.SLOWDOWN){ characterMoveTree.start(MovementRelativeFacing.FORWARD); } diff --git a/src/main/java/electrosphere/server/ai/creature/party/PartyFollower.java b/src/main/java/electrosphere/server/ai/creature/party/PartyFollower.java index dcd57f4c..bbee68fe 100644 --- a/src/main/java/electrosphere/server/ai/creature/party/PartyFollower.java +++ b/src/main/java/electrosphere/server/ai/creature/party/PartyFollower.java @@ -43,7 +43,7 @@ public class PartyFollower extends AI { Vector3d characterPosition = EntityUtils.getPosition(character); Vector3d moveVector = new Vector3d(targetPosition).sub(characterPosition).normalize(); CreatureUtils.setFacingVector(character, new Vector3d((float)moveVector.x,(float)moveVector.y,(float)moveVector.z)); - GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.getEntityMovementTree(character); + GroundMovementTree characterMoveTree = (GroundMovementTree)CreatureUtils.serverGetEntityMovementTree(character); if(characterMoveTree.getState()==GroundMovementTree.MovementTreeState.IDLE || characterMoveTree.getState()==GroundMovementTree.MovementTreeState.SLOWDOWN){ characterMoveTree.start(MovementRelativeFacing.FORWARD); } diff --git a/src/main/java/electrosphere/server/datacell/EnvironmentGenerator.java b/src/main/java/electrosphere/server/content/EnvironmentGenerator.java similarity index 61% rename from src/main/java/electrosphere/server/datacell/EnvironmentGenerator.java rename to src/main/java/electrosphere/server/content/EnvironmentGenerator.java index 8f36eeb0..3e47455c 100644 --- a/src/main/java/electrosphere/server/datacell/EnvironmentGenerator.java +++ b/src/main/java/electrosphere/server/content/EnvironmentGenerator.java @@ -1,15 +1,17 @@ -package electrosphere.server.datacell; +package electrosphere.server.content; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.foliage.FoliageUtils; +import electrosphere.server.datacell.ServerDataCell; import java.util.List; import java.util.Random; import org.joml.Quaternionf; import org.joml.Vector3f; +import org.joml.Vector3i; /** * @@ -18,14 +20,14 @@ import org.joml.Vector3f; public class EnvironmentGenerator { - public static void generatePlains(List entityList, int worldX, int worldY, long randomizer){ + public static void generatePlains(ServerDataCell cell, Vector3i worldPos, long randomizer){ Random rand = new Random(randomizer); int targetNum = (int)(rand.nextFloat() * 10) + 10; for(int i = 0; i < targetNum; i++){ Entity newTree = FoliageUtils.spawnBasicFoliage("FallOak1"); - entityList.add(newTree); - double posX = worldX * Globals.serverWorldData.getDynamicInterpolationRatio() + (float)(rand.nextFloat() * Globals.serverWorldData.getDynamicInterpolationRatio()); - double posZ = worldY * Globals.serverWorldData.getDynamicInterpolationRatio() + (float)(rand.nextFloat() * Globals.serverWorldData.getDynamicInterpolationRatio()); + cell.getScene().registerEntity(newTree); + double posX = worldPos.x * Globals.serverWorldData.getDynamicInterpolationRatio() + (float)(rand.nextFloat() * Globals.serverWorldData.getDynamicInterpolationRatio()); + double posZ = worldPos.z * Globals.serverWorldData.getDynamicInterpolationRatio() + (float)(rand.nextFloat() * Globals.serverWorldData.getDynamicInterpolationRatio()); double posY = Globals.serverTerrainManager.getHeightAtPosition(posX, posZ); // System.out.println("Spawning tree at: " + posX + "," + posY + "," + posZ); // CollisionObjUtils.positionCharacter(newTree, new Vector3f(posX,posY,posZ)); diff --git a/src/main/java/electrosphere/server/content/ServerContentManager.java b/src/main/java/electrosphere/server/content/ServerContentManager.java new file mode 100644 index 00000000..f59ab2ef --- /dev/null +++ b/src/main/java/electrosphere/server/content/ServerContentManager.java @@ -0,0 +1,23 @@ +package electrosphere.server.content; + +import org.joml.Vector3i; + +import electrosphere.engine.Globals; +import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.pathfinding.NavMeshUtils; + +public class ServerContentManager { + + + public void generateContentForDataCell(Vector3i worldPos, ServerDataCell cell){ + if(!Globals.serverWorldData.isArena()){ //in other words, if not arena mode + //if on disk (has already been generated) + //else create from scratch + EnvironmentGenerator.generatePlains(cell, worldPos, Globals.serverTerrainManager.getRandomizerAtPoint(worldPos.x, worldPos.z)); + } + cell.setNavMesh(NavMeshUtils.createMeshFromChunk(Globals.serverTerrainManager.getChunk(worldPos.x, worldPos.z),Globals.navMeshManager.getBlockerCache().getBlocker(worldPos.x, worldPos.z))); + } + + + +} diff --git a/src/main/java/electrosphere/server/datacell/DataCellManager.java b/src/main/java/electrosphere/server/datacell/DataCellManager.java deleted file mode 100644 index 49ac9803..00000000 --- a/src/main/java/electrosphere/server/datacell/DataCellManager.java +++ /dev/null @@ -1,209 +0,0 @@ -package electrosphere.server.datacell; - -import electrosphere.engine.Globals; -import electrosphere.entity.Entity; -import electrosphere.entity.EntityUtils; -import electrosphere.game.collision.CommonWorldData; -import electrosphere.game.server.world.ServerWorldData; -import electrosphere.logger.LoggerInterface; -import electrosphere.net.parser.net.message.NetworkMessage; -import electrosphere.net.server.player.Player; - -import java.util.LinkedList; -import java.util.List; -import org.joml.Vector3d; -import org.joml.Vector3f; - -/** - * - * @author satellite - */ -public class DataCellManager { - - List loadedDataCells = new LinkedList(); - //these are going to be the natural ground grid of data cells, but we're going to have more than this - ServerDataCell[][] groundDataCells; - int discreteWorldSize; - //this is the cell that all players loading into the game (via connection startup, death, etc) reside in - ServerDataCell loadingCell; - - public DataCellManager(ServerWorldData data) { - discreteWorldSize = data.getWorldSizeDiscrete(); - groundDataCells = new ServerDataCell[discreteWorldSize][discreteWorldSize]; - } - - public void init(){ - loadingCell = new ServerDataCell(); - } - - public ServerDataCell createNewCell(){ - ServerDataCell newCell = new ServerDataCell(); - loadedDataCells.add(newCell); - return newCell; - } - - public void deregisterCell(ServerDataCell cell){ - loadedDataCells.remove(cell); - } - - - public void addPlayerToGroundCells(Player player){ - int playerSimulationRadius = player.getSimulationRadius(); - int oldX = player.getWorldX(); - int oldY = player.getWorldY(); - for(int x = oldX - playerSimulationRadius; x < oldX + playerSimulationRadius + 1; x++){ - for(int y = oldY - playerSimulationRadius; y < oldY + playerSimulationRadius + 1; y++){ - if( - x >= 0 && x < discreteWorldSize && - y >= 0 && y < discreteWorldSize - ){ - LoggerInterface.loggerEngine.DEBUG("DataCellManager: Add player to " + x + " " + y); - if(groundDataCells[x][y] != null){ - groundDataCells[x][y].addPlayer(player); - } else { - //create data cell - groundDataCells[x][y] = ServerDataCell.loadCellAtWorldCoord(x, y); - //add player - groundDataCells[x][y].addPlayer(player); - } - } - } - } - } - - public void movePlayerGroundCells(Player player, int newX, int newY){ - int playerSimulationRadius = player.getSimulationRadius(); - int oldX = player.getWorldX(); - int oldY = player.getWorldY(); - player.setWorldX(newX); - player.setWorldY(newY); -// System.out.println("=======" + "SET" + newX + " " + newY + " FROM " + oldX + " " + oldY + "========"); - // int removals = 0; - // int additions = 0; - for(int x = oldX - playerSimulationRadius; x < oldX + playerSimulationRadius + 1; x++){ - for(int y = oldY - playerSimulationRadius; y < oldY + playerSimulationRadius + 1; y++){ - if( - x >= 0 && x < discreteWorldSize && - y >= 0 && y < discreteWorldSize && - (x < newX - playerSimulationRadius || x > newX + playerSimulationRadius || y < newY - playerSimulationRadius || y > newY + playerSimulationRadius) - ){ - if(groundDataCells[x][y] != null){ - if(groundDataCells[x][y].containsPlayer(player)){ - // removals++; - groundDataCells[x][y].removePlayer(player); - } - } - } - } - } - for(int x = newX - playerSimulationRadius; x < newX + playerSimulationRadius + 1; x++){ - for(int y = newY - playerSimulationRadius; y < newY + playerSimulationRadius + 1; y++){ - if( - x >= 0 && x < discreteWorldSize && - y >= 0 && y < discreteWorldSize && - (x < oldX - playerSimulationRadius || x > oldX + playerSimulationRadius || y < oldY - playerSimulationRadius || y > oldY + playerSimulationRadius) - ){ -// System.out.println("Add player to " + x + " " + y); - if(groundDataCells[x][y] != null){ - groundDataCells[x][y].addPlayer(player); - } else { - //create data cell - groundDataCells[x][y] = ServerDataCell.loadCellAtWorldCoord(x, y); - //add player - groundDataCells[x][y].addPlayer(player); - } - // 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); - } - - public void removePlayer(Player player){ - throw new UnsupportedOperationException("Removing players from the data cell manager isn't supported -- DataCellManager -- removePlayer(Player player)"); - } - - public boolean updatePlayerGroundCellPositions(){ - boolean playerChangedChunk = false; - for(Player player : Globals.playerManager.getPlayers()){ - Entity playerEntity = player.getPlayerEntity(); - if(playerEntity != null && !loadingCell.containsPlayer(player)){ - Vector3d position = EntityUtils.getPosition(playerEntity); - int currentWorldX = Globals.serverWorldData.convertRealToChunkSpace(position.x); - int currentWorldY = Globals.serverWorldData.convertRealToChunkSpace(position.z); - if(currentWorldX != player.getWorldX() || currentWorldY != player.getWorldY()){ - movePlayerGroundCells(player,currentWorldX,currentWorldY); - playerChangedChunk = true; - } - } - } - return playerChangedChunk; - } - - public void sendNetworkMessageToChunk(NetworkMessage message, int worldX, int worldY){ - if( - //in bounds of array - worldX >= 0 && worldX < groundDataCells.length && - worldY >= 0 && worldY < groundDataCells[0].length && - //isn't null - groundDataCells[worldX][worldY] != null - ){ - groundDataCells[worldX][worldY].broadcastNetworkMessage(message); - } - } - - public void unloadPlayerlessChunks(){ - //TODO: implement and actually call it - } - - public ServerDataCell getDataCellAtPoint(Vector3d point){ - ServerDataCell rVal = null; - int worldX = Globals.serverWorldData.convertRealToChunkSpace(point.x); - int worldZ = Globals.serverWorldData.convertRealToChunkSpace(point.z); - if( - //in bounds of array - worldX >= 0 && worldX < groundDataCells.length && - worldZ >= 0 && worldZ < groundDataCells[0].length && - //isn't null - groundDataCells[worldX][worldZ] != null - ){ - rVal = groundDataCells[worldX][worldZ]; - } - return rVal; - } - - public ServerDataCell tryCreateGroundDataCell(Vector3d point){ - int worldX = Globals.serverWorldData.convertRealToChunkSpace(point.x); - int worldZ = Globals.serverWorldData.convertRealToChunkSpace(point.z); - if( - //in bounds of array - worldX >= 0 && worldX < groundDataCells.length && - worldZ >= 0 && worldZ < groundDataCells[0].length && - //isn't null - groundDataCells[worldX][worldZ] == null - ){ - groundDataCells[worldX][worldZ] = new ServerDataCell(); - } - return groundDataCells[worldX][worldZ]; - } - - - /** - * If we're spawning an entity for the first time, call this method with the cell you want it to start in. - * It adds the entity to the given cell and initializes it for all players in said cell - * @param entity The entity we are initializing - * @param cell The cell we are wanting to initialize the entity in - */ - public void initializeServerSideEntity(Entity entity, ServerDataCell cell){ - //add the entity to the cell - cell.addEntity(entity); - //send the entity to all players - cell.initializeEntityForNewPlayers(entity, null); - } - - - -} diff --git a/src/main/java/electrosphere/server/datacell/EntityDataCellMapper.java b/src/main/java/electrosphere/server/datacell/EntityDataCellMapper.java new file mode 100644 index 00000000..1661de8e --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/EntityDataCellMapper.java @@ -0,0 +1,51 @@ +package electrosphere.server.datacell; + +import java.util.HashMap; +import java.util.Map; + +import electrosphere.entity.Entity; + +/** + * The idea with this class is to break out the entity->server data cell mapping out from DataCellManager so that the latter can focus on just managing the existance of data cells + */ +public class EntityDataCellMapper { + + // The map of entity -> server data cell + Map entityDataCellMap = new HashMap(); + + /** + * Registers an entity into the map. Should be called every time any entity is created on the server. + * @param entity The entity that was just created + * @param serverDataCell The server data cell to register this entity to + */ + public void registerEntity(Entity entity, ServerDataCell serverDataCell){ + entityDataCellMap.put(entity, serverDataCell); + } + + /** + * Gets a server data cell that an entity corresponds to + * @param entity The entity to search by + * @return The server data cell that the entity is inside of + */ + public ServerDataCell getEntityDataCell(Entity entity){ + return entityDataCellMap.get(entity); + } + + /** + * Updates the server data cell that an entity is inside of. Should be called every time an entity changes server data cell. + * @param entity The entity to update + * @param serverDataCell The new server data cell for the entity + */ + public void updateEntityCell(Entity entity, ServerDataCell serverDataCell){ + entityDataCellMap.put(entity, serverDataCell); + } + + /** + * Ejects an entity from the server data cell map. Should only be called when an entity is being destroyed. Furthermore, should be called every time an entity is destroyed. + * @param entity The entity to eject + */ + public void ejectEntity(Entity entity){ + entityDataCellMap.remove(entity); + } + +} diff --git a/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java new file mode 100644 index 00000000..17e27f64 --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/GriddedDataCellManager.java @@ -0,0 +1,249 @@ +package electrosphere.server.datacell; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import org.joml.Vector3d; +import org.joml.Vector3i; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.Scene; +import electrosphere.game.server.world.ServerWorldData; +import electrosphere.logger.LoggerInterface; +import electrosphere.net.server.player.Player; +import electrosphere.server.datacell.interfaces.DataCellManager; + +/** + * Implementation of DataCellManager that lays out cells in a logical grid (array). Useful for eg 3d terrain gridded world. + */ +public class GriddedDataCellManager implements DataCellManager { + //these are going to be the natural ground grid of data cells, but we're going to have more than this + ServerDataCell[][][] groundDataCells; + Set loadedCells; + int discreteWorldSize; + //parent realm + Realm parent; + + /** + * Constructor + * @param parent The gridded data cell manager's parent realm + */ + public GriddedDataCellManager(Realm parent) { + this.parent = parent; + } + + public void init(ServerWorldData data){ + discreteWorldSize = data.getWorldSizeDiscrete(); + groundDataCells = new ServerDataCell[discreteWorldSize][discreteWorldSize][discreteWorldSize]; + loadedCells = new HashSet(); + } + + /** + * Adds a player to the realm that this manager controls. Should do this intelligently based on the player's location + * @param player The player + */ + public void addPlayerToRealm(Player player){ + int playerSimulationRadius = player.getSimulationRadius(); + Vector3i worldPos = player.getWorldPos(); + for(int x = worldPos.x - playerSimulationRadius; x < worldPos.x + playerSimulationRadius + 1; x++){ + for(int y = worldPos.y - playerSimulationRadius; y < worldPos.y + playerSimulationRadius + 1; y++){ + for(int z = worldPos.z - playerSimulationRadius; z < worldPos.z + playerSimulationRadius + 1; z++){ + if( + x >= 0 && x < discreteWorldSize && + y >= 0 && y < discreteWorldSize && + z >= 0 && z < discreteWorldSize + ){ + LoggerInterface.loggerEngine.DEBUG("TerrainDataCellManager: Add player to " + x + " " + y); + if(groundDataCells[x][y][z] != null){ + groundDataCells[x][y][z].addPlayer(player); + } else { + //create data cell + groundDataCells[x][y][z] = ServerDataCell.createServerDataCell(new Scene()); + loadedCells.add(groundDataCells[x][y][z]); + //generate/handle content for new server data cell + + //add player + groundDataCells[x][y][z].addPlayer(player); + } + } + } + } + } + } + + /** + * Moves a player to a new position + * @param player The player + * @param newPosition The new position + */ + public void movePlayer(Player player, Vector3i newPosition){ + 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 < discreteWorldSize && + y >= 0 && y < discreteWorldSize && + z >= 0 && z < discreteWorldSize && + ( + x < newPosition.x - playerSimulationRadius || + x > newPosition.x + playerSimulationRadius || + y < newPosition.y - playerSimulationRadius || + y > newPosition.y + playerSimulationRadius || + z < newPosition.z - playerSimulationRadius || + z > newPosition.z + playerSimulationRadius + ) + ){ + if(groundDataCells[x][y][z] != null){ + if(groundDataCells[x][y][z].containsPlayer(player)){ + // removals++; + groundDataCells[x][y][z].removePlayer(player); + } + } + } + } + } + } + for(int x = newPosition.x - playerSimulationRadius; x < newPosition.x + playerSimulationRadius + 1; x++){ + for(int y = newPosition.y - playerSimulationRadius; y < newPosition.y + playerSimulationRadius + 1; y++){ + for(int z = newPosition.x - playerSimulationRadius; z < newPosition.z + playerSimulationRadius + 1; z++){ + if( + x >= 0 && x < discreteWorldSize && + y >= 0 && y < discreteWorldSize && + z >= 0 && z < discreteWorldSize && + ( + x < oldPosition.x - playerSimulationRadius || + x > oldPosition.x + playerSimulationRadius || + y < oldPosition.y - playerSimulationRadius || + y > oldPosition.y + playerSimulationRadius || + z < oldPosition.z - playerSimulationRadius || + z > oldPosition.z + playerSimulationRadius + ) + ){ + // System.out.println("Add player to " + x + " " + y); + if(groundDataCells[x][y][z] != null){ + groundDataCells[x][y][z].addPlayer(player); + } else { + //create data cell + groundDataCells[x][y][z] = parent.createNewCell(); + //add player + groundDataCells[x][y][z].addPlayer(player); + } + // 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); + } + + /** + * For every player, looks at their entity and determines what data cell they should be considered inside of + * @return True if the player changed cell, false otherwise + */ + public boolean updatePlayerPositions(){ + boolean playerChangedChunk = false; + for(Player player : Globals.playerManager.getPlayers()){ + Entity playerEntity = player.getPlayerEntity(); + if(playerEntity != null && !parent.getLoadingDataCell().containsPlayer(player)){ + Vector3d position = EntityUtils.getPosition(playerEntity); + int currentWorldX = Globals.serverWorldData.convertRealToChunkSpace(position.x); + int currentWorldY = Globals.serverWorldData.convertRealToChunkSpace(position.y); + int currentWorldZ = Globals.serverWorldData.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; + } + } + } + return playerChangedChunk; + } + + /** + * Get data cell at a given real point in this realm + * @param point The real point + * @return Either the data cell if found, or null if not found + */ + public ServerDataCell getDataCellAtPoint(Vector3d point){ + ServerDataCell rVal = null; + int worldX = Globals.serverWorldData.convertRealToChunkSpace(point.x); + int worldY = Globals.serverWorldData.convertRealToChunkSpace(point.y); + int worldZ = Globals.serverWorldData.convertRealToChunkSpace(point.z); + if( + //in bounds of array + worldX >= 0 && worldX < groundDataCells.length && + worldY >= 0 && worldY < groundDataCells[0].length && + worldZ >= 0 && worldZ < groundDataCells[0][0].length && + //isn't null + groundDataCells[worldX][worldY][worldZ] != null + ){ + rVal = groundDataCells[worldX][worldY][worldZ]; + } + return rVal; + } + + /** + * Tries to create a data cell at a given real point + * @param point The real point + * @return The data cell if created, null otherwise + */ + public ServerDataCell tryCreateCellAtPoint(Vector3d point){ + int worldX = Globals.serverWorldData.convertRealToChunkSpace(point.x); + int worldY = Globals.serverWorldData.convertRealToChunkSpace(point.y); + int worldZ = Globals.serverWorldData.convertRealToChunkSpace(point.z); + if( + //in bounds of array + worldX >= 0 && worldX < groundDataCells.length && + worldY >= 0 && worldY < groundDataCells[0].length && + worldZ >= 0 && worldZ < groundDataCells[0][0].length && + //isn't null + groundDataCells[worldX][worldY][worldZ] == null + ){ + groundDataCells[worldX][worldY][worldZ] = ServerDataCell.createServerDataCell(new Scene()); + loadedCells.add(groundDataCells[worldX][worldY][worldZ]); + } + return groundDataCells[worldX][worldY][worldZ]; + } + + /** + * Gets a data cell at a given world position + * @param position The world position + * @return The data cell if found, null otherwise + */ + public ServerDataCell getCellAtWorldPosition(Vector3i position){ + if( + //in bounds of array + position.x >= 0 && position.x < groundDataCells.length && + position.y >= 0 && position.y < groundDataCells[0].length && + position.z >= 0 && position.z < groundDataCells[0][0].length && + //isn't null + groundDataCells[position.x][position.y][position.z] != null + ){ + return groundDataCells[position.x][position.y][position.z]; + } + return null; + } + + + /** + * Calls the simulate function on all loaded cells + */ + public void simulate(){ + for(ServerDataCell cell : loadedCells){ + Globals.microSimulation.simulate(cell, parent.getHitboxManager()); + } + } + +} diff --git a/src/main/java/electrosphere/server/datacell/Realm.java b/src/main/java/electrosphere/server/datacell/Realm.java new file mode 100644 index 00000000..e42b5564 --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/Realm.java @@ -0,0 +1,190 @@ +package electrosphere.server.datacell; + +import electrosphere.engine.Globals; +import electrosphere.engine.Main; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; +import electrosphere.entity.Scene; +import electrosphere.entity.types.hitbox.HitboxManager; +import electrosphere.game.collision.CollisionEngine; +import electrosphere.game.collision.CommonWorldData; +import electrosphere.game.server.world.ServerWorldData; +import electrosphere.logger.LoggerInterface; +import electrosphere.net.parser.net.message.NetworkMessage; +import electrosphere.net.server.Server; +import electrosphere.net.server.player.Player; +import electrosphere.server.datacell.interfaces.DataCellManager; + +import java.util.LinkedList; +import java.util.List; +import org.joml.Vector3d; +import org.joml.Vector3f; +import org.joml.Vector3i; + +/** + * Manages data cells on the server side + */ +public class Realm { + + List loadedDataCells = new LinkedList(); + //this is the cell that all players loading into the game (via connection startup, death, etc) reside in + ServerDataCell loadingCell = new ServerDataCell(new Scene()); + + //resolver for location -> data cell within this realm + // DataCellLocationResolver dataCellLocationResolver; + + //resolver for entity -> data cell within this realm + EntityDataCellMapper entityDataCellMapper; + + //provides functions for relating data cells to physical locations (eg creating cells, deleting cells, etc) + DataCellManager dataCellManager; + + //Main entity physics collision checking engine + CollisionEngine collisionEngine; + + //Hitbox manager for the realm + HitboxManager hitboxManager; + + /** + * Realm constructor + * @param collisionEngine The collision engine for the realm + * @param hitboxManager The hitbox manager for the realm + */ + protected Realm(CollisionEngine collisionEngine, HitboxManager hitboxManager){ + this.collisionEngine = collisionEngine; + this.hitboxManager = hitboxManager; + } + + /** + * Creates a new data cell + * @return The new data cell + */ + public ServerDataCell createNewCell(){ + ServerDataCell newCell = new ServerDataCell(new Scene()); + loadedDataCells.add(newCell); + return newCell; + } + + /** + * Removes a data cell from tracking in this data cell manager + * @param cell The data cell to no longer keep track of + */ + public void deregisterCell(ServerDataCell cell){ + loadedDataCells.remove(cell); + } + + + /** + * Gets the default loading data cell + * @return The default loading data cell + */ + public ServerDataCell getLoadingDataCell(){ + return loadingCell; + } + + /** + * Broadcasts a message to all players in a certain serverdatacell + * @param message The message to send + * @param cell The serverdatacell + */ + public void sendNetworkMessageToChunk(NetworkMessage message, Entity e){ + //solve for what data cell the entitiy is in + ServerDataCell cell = Globals.entityDataCellMapper.getEntityDataCell(e); + cell.broadcastNetworkMessage(message); + } + + /** + * Unloads all chunks that haven't had players in them for a set amount of time + */ + public void unloadPlayerlessChunks(){ + //TODO: implement and actually call it + } + + + /** + * If we're spawning an entity for the first time, call this method with the cell you want it to start in. + * It adds the entity to the given cell and initializes it for all players in said cell + * @param entity The entity we are initializing + * @param cell The cell we are wanting to initialize the entity in + */ + public void initializeServerSideEntity(Entity entity, ServerDataCell cell){ + //register entity to this realm + Globals.realmManager.mapEntityToRealm(entity, this); + //add the entity to the cell + cell.getScene().registerEntity(entity); + //send the entity to all players + cell.initializeEntityForNewPlayers(entity, null); + //register to entity data cell mapper + 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 + * @return The data cell manager for this realm + */ + public DataCellManager getDataCellManager(){ + 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 + */ + protected void setDataCellManager(DataCellManager dataCellManager){ + this.dataCellManager = dataCellManager; + } + + /** + * Gets the collision engine for physics collision checking in this realm + * @return The collision engine + */ + public CollisionEngine getCollisionEngine(){ + return this.collisionEngine; + } + + /** + * Gets the hitbox manager backing this realm + * @return The hitbox manager + */ + public HitboxManager getHitboxManager(){ + return this.hitboxManager; + } + + /** + * Tells the data cell manager to simulate all loaded cells + */ + protected void simulate(){ + //simulate bullet physics engine step + collisionEngine.simulatePhysics(Main.deltaFrames); + //main simulation + dataCellManager.simulate(); + //data cell manager update misc variables (player positions, unload not-in-use cells) + if(dataCellManager != null){ + // boolean playerHasChangedChunk = dataCellManager.updatePlayerGroundCellPositions(); + // if(playerHasChangedChunk){ + // dataCellManager.unloadPlayerlessChunks(); + // } + } + //clear collidable impulse lists + collisionEngine.clearCollidableImpulseLists(); + } + + +} diff --git a/src/main/java/electrosphere/server/datacell/RealmManager.java b/src/main/java/electrosphere/server/datacell/RealmManager.java new file mode 100644 index 00000000..a93e37a3 --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/RealmManager.java @@ -0,0 +1,104 @@ +package electrosphere.server.datacell; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import electrosphere.entity.Entity; +import electrosphere.entity.types.hitbox.HitboxManager; +import electrosphere.game.collision.CollisionEngine; +import electrosphere.game.server.world.ServerWorldData; + +/** + * Manages all realms for the engine. Should be a singleton + */ +public class RealmManager { + + //All realms in this manager + Set realms = new HashSet(); + //Map of entities to the realm the entity is in + Map entityToRealmMap = new HashMap(); + + + /** + * Constructor + */ + public RealmManager(){ + + } + + + /** + * Creates a realm + * @return The realm + */ + public Realm createRealm(){ + return new Realm(new CollisionEngine(), new HitboxManager()); + } + + /** + * Creates a realm that uses a gridded layout (ie an array of cells in 3d space) + * @return The realm + */ + public Realm createGriddedRealm(ServerWorldData serverWorldData){ + Realm realm = new Realm(new CollisionEngine(), new HitboxManager()); + //create function classes + GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm); + EntityDataCellMapper entityDataCellMapper = new EntityDataCellMapper(); + //init gridded manager + griddedDataCellManager.init(serverWorldData); + //add function classes to realm + realm.setDataCellManager(griddedDataCellManager); + realm.setEntityDataCellMapper(entityDataCellMapper); + //register within the manager + realms.add(realm); + return realm; + } + + /** + * Maps an entity to a realm + * @param entity The entity + * @param realm The realm + */ + public void mapEntityToRealm(Entity entity, Realm realm){ + entityToRealmMap.put(entity, realm); + } + + /** + * Removes the entity from tracking in this realm manager + * @param entity The entity to remove + */ + public void removeEntity(Entity entity){ + entityToRealmMap.remove(entity); + } + + /** + * Gets the realm an entity is inside of + * @param entity The entity + * @return The realm, or null if the entity is not inside a realm + */ + public Realm getEntityRealm(Entity entity){ + return entityToRealmMap.get(entity); + } + + /** + * Gets the set containing all realms in the manager + * @return The set containing all realms in the manager + */ + public Set getRealms(){ + return realms; + } + + + /** + * Simulates all realms in this manager + */ + public void simulate(){ + for(Realm realm : realms){ + realm.simulate(); + } + } + + +} diff --git a/src/main/java/electrosphere/server/datacell/ServerDataCell.java b/src/main/java/electrosphere/server/datacell/ServerDataCell.java index 34293f95..c4e177a6 100644 --- a/src/main/java/electrosphere/server/datacell/ServerDataCell.java +++ b/src/main/java/electrosphere/server/datacell/ServerDataCell.java @@ -2,6 +2,7 @@ package electrosphere.server.datacell; import electrosphere.engine.Globals; import electrosphere.entity.Entity; +import electrosphere.entity.Scene; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.types.structure.StructureUtils; @@ -9,6 +10,7 @@ import electrosphere.game.server.character.Character; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.parser.net.message.NetworkMessage; import electrosphere.net.server.player.Player; +import electrosphere.server.content.EnvironmentGenerator; import electrosphere.server.pathfinding.NavMeshUtils; import electrosphere.server.pathfinding.navmesh.NavMesh; @@ -26,9 +28,9 @@ import java.util.List; */ public class ServerDataCell { - List loadedEntities = new LinkedList(); List activePlayers = new LinkedList(); NavMesh navMesh; + Scene scene; /** @@ -36,20 +38,13 @@ public class ServerDataCell { * first comes into range of the cell. * @param virtualCell */ - ServerDataCell(){ - + ServerDataCell(Scene scene){ + this.scene = scene; } - - public static ServerDataCell loadCellAtWorldCoord(int worldX, int worldY){ - ServerDataCell rVal = new ServerDataCell(); - if(!Globals.serverWorldData.isArena()){ //in other words, if not arena mode - //if on disk (has already been generated) - //else create from scratch - EnvironmentGenerator.generatePlains(rVal.loadedEntities, worldX, worldY, Globals.serverTerrainManager.getRandomizerAtPoint(worldX, worldY)); - } - rVal.navMesh = NavMeshUtils.createMeshFromChunk(Globals.serverTerrainManager.getChunk(worldX, worldY),Globals.navMeshManager.getBlockerCache().getBlocker(worldX, worldY)); - return rVal; + + protected static ServerDataCell createServerDataCell(Scene scene){ + return new ServerDataCell(scene); } /** @@ -88,24 +83,24 @@ public class ServerDataCell { throw new UnsupportedOperationException("Not implemented yet"); } - /** - * This should be used to translate an entity from one data cell to another. - * @param e - */ - protected void addEntity(Entity e){ - loadedEntities.add(e); - } + // /** + // * This should be used to translate an entity from one data cell to another. + // * @param e + // */ + // protected void addEntity(Entity e){ + // loadedEntities.add(e); + // } - /** - * Intention of this function is to entirely remove the entity from microlevel simulation. - * This should be conbined with code to convert the entity into a tracked macrolevel character. - * The previous should not be true if you're tracking something inconsequential like - * a rabbit or something. Then just delete it. - * @param e - */ - public void removeEntity(Entity e){ - loadedEntities.remove(e); - } + // /** + // * Intention of this function is to entirely remove the entity from microlevel simulation. + // * This should be conbined with code to convert the entity into a tracked macrolevel character. + // * The previous should not be true if you're tracking something inconsequential like + // * a rabbit or something. Then just delete it. + // * @param e + // */ + // public void removeEntity(Entity e){ + // loadedEntities.remove(e); + // } /** * Broadcast a message to all players within range of this cell. @@ -123,7 +118,7 @@ public class ServerDataCell { * Serializes the given creature to all players in this cell that aren't in the provided list of players * whom have already received spawn messages for the entity * @param creature The creature entity to spawn - * @param previousCell The datacell the creature was previously in, which we will use to selectively not send the creature + * @param previousCell The datacell the creature was previously in, which we will use to selectively not send the creature. Pass null if there is no previous cell (eg on first initialization). */ public void initializeEntityForNewPlayers(Entity creature, ServerDataCell previousCell){ for(Player player : this.activePlayers){ @@ -142,10 +137,8 @@ public class ServerDataCell { * Commonly, this should be called when a player is added to the cell */ void serializeStateToPlayer(Player player){ - if(player != Globals.clientPlayer){ - for(Entity entity : loadedEntities){ - serializeEntityToPlayer(entity,player); - } + for(Entity entity : scene.getEntityList()){ + serializeEntityToPlayer(entity,player); } } @@ -186,9 +179,11 @@ public class ServerDataCell { public static void moveEntityFromCellToCell(Entity entity, ServerDataCell oldCell, ServerDataCell newCell){ //swap which holds the entity if(oldCell != null){ - oldCell.removeEntity(entity); + oldCell.getScene().deregisterEntity(entity); } - newCell.addEntity(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){ @@ -211,5 +206,21 @@ public class ServerDataCell { } } } + + /** + * Gets the scene backing this data cell + * @return The scene backing this data cell + */ + public Scene getScene(){ + return scene; + } + + /** + * Sets the nav mesh of this server data cell + * @param navMesh The nav mesh to store + */ + public void setNavMesh(NavMesh navMesh){ + this.navMesh = navMesh; + } } diff --git a/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java b/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java new file mode 100644 index 00000000..1f1f383b --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/interfaces/DataCellManager.java @@ -0,0 +1,59 @@ +package electrosphere.server.datacell.interfaces; + +import org.joml.Vector3d; +import org.joml.Vector3i; + +import electrosphere.net.server.player.Player; +import electrosphere.server.datacell.ServerDataCell; + +/** + * Interface for manager class for creating and destroying cells with respect to spatial locations + */ +public interface DataCellManager { + + /** + * Adds a player to the realm that this manager controls. Should do this intelligently based on the player's location + * @param player The player + */ + public void addPlayerToRealm(Player player); + + /** + * Moves a player to a new position + * @param player The player + * @param newPosition The new position + */ + public void movePlayer(Player player, Vector3i newPosition); + + /** + * Updates player positions based on the location of the player's current entity + * @return True if a player changed cell, false otherwise + */ + public boolean updatePlayerPositions(); + + /** + * Get data cell at a given real point in this realm + * @param point The real point + * @return Either the data cell if found, or null if not found + */ + public ServerDataCell getDataCellAtPoint(Vector3d point); + + /** + * Tries to create a data cell at a given real point + * @param point The real point + * @return The data cell if created or if already exists, null if cannot create and does not already exist + */ + public ServerDataCell tryCreateCellAtPoint(Vector3d point); + + /** + * Gets a data cell at a given world position + * @param position The world position + * @return The data cell if found, null otherwise + */ + public ServerDataCell getCellAtWorldPosition(Vector3i position); + + /** + * Calls the simulate function on all loaded cells + */ + public void simulate(); + +} diff --git a/src/main/java/electrosphere/server/datacell/physics/DataCellPhysicsManager.java b/src/main/java/electrosphere/server/datacell/physics/DataCellPhysicsManager.java new file mode 100644 index 00000000..30515299 --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/physics/DataCellPhysicsManager.java @@ -0,0 +1,639 @@ +package electrosphere.server.datacell.physics; + +import electrosphere.engine.Globals; +import electrosphere.game.client.terrain.manager.ClientTerrainManager; +import electrosphere.game.server.terrain.manager.ServerTerrainManager; +import electrosphere.game.terrain.processing.TerrainInterpolator; +import electrosphere.game.client.world.ClientWorldData; +import electrosphere.game.collision.CommonWorldData; +import electrosphere.net.parser.net.message.TerrainMessage; +import electrosphere.renderer.ShaderProgram; +import java.util.Arrays; +import java.util.HashMap; + +import org.joml.Vector2i; +import org.joml.Vector3d; +import org.joml.Vector3f; + +/** + * This managed spinning up and tearing down physics on the server side specifically for terrain meshes + */ +public class DataCellPhysicsManager { + //the center of this cell manager's array in cell space + int cellX; + int cellY; + + + //the dimensions of the world that this cell manager can handles + int cellWidth; + int cellHeight; + + //the width of a minicell in this manager + int miniCellWidth; + + //all currently displaying mini cells + PhysicsDataCell[][] cells; + boolean[][] valid; + boolean[][] updateable; + boolean[][] hasRequested; + boolean[][] needsPhysics; + boolean[][] hasPhysics; + + + int drawRadius = 5; + int drawStepdownInterval = 3; + int drawStepdownValue = 25; + + int physicsRadius = 3; + + int worldBoundDiscreteMin = 0; + int worldBoundDiscreteMax = 0; + + //metadata about the game world + CommonWorldData commonWorldData; + + //client terrain manager + // ClientTerrainManager clientTerrainManager; + + + //ready to start updating? + boolean update = false; + + //controls whether we try to generate the drawable entities + //we want this to be false when in server-only mode + boolean generateDrawables = false; + + + + public DataCellPhysicsManager(CommonWorldData commonWorldData, int discreteX, int discreteY){ + this.commonWorldData = commonWorldData; + worldBoundDiscreteMax = (int)(commonWorldData.getWorldBoundMin().x / commonWorldData.getDynamicInterpolationRatio() * 1.0f); + // this.clientTerrainManager = clientTerrainManager; + cells = new PhysicsDataCell[drawRadius * 2 + 1][drawRadius * 2 + 1]; + valid = new boolean[drawRadius * 2 + 1][drawRadius * 2 + 1]; + updateable = new boolean[drawRadius * 2 + 1][drawRadius * 2 + 1]; + hasRequested = new boolean[drawRadius * 2 + 1][drawRadius * 2 + 1]; + needsPhysics = new boolean[physicsRadius * 2 + 1][physicsRadius * 2 + 1]; + hasPhysics = new boolean[physicsRadius * 2 + 1][physicsRadius * 2 + 1]; + for(int x = 0; x < drawRadius * 2 + 1; x++){ + for(int y = 0; y < drawRadius * 2 + 1; y++){ + valid[x][y] = false; + updateable[x][y] = false; + hasRequested[x][y] = false; + } + } + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + for(int y = 0; y < physicsRadius * 2 + 1; y++){ + needsPhysics[x][y] = true; + hasPhysics[x][y] = false; + } + } + cellX = discreteX; + cellY = discreteY; + + drawRadius = Globals.userSettings.getGraphicsPerformanceLODChunkRadius(); + drawStepdownInterval = Globals.userSettings.getGameplayPhysicsCellRadius(); + physicsRadius = Globals.userSettings.getGameplayPhysicsCellRadius(); + + update = true; + } + + DataCellPhysicsManager(){ + + } + + public int getCellX(){ + return cellX; + } + + public int getCellY(){ + return cellY; + } + + public void setCellX(int x){ + cellX = x; + } + + public void setCellY(int y){ + cellY = y; + } + + public void setCell(Vector2i cellPos){ + cellX = cellPos.x; + cellY = cellPos.y; + } + + void updateInvalidCell(){ + int targetX = 0; + int targetY = 0; + boolean found = false; + for(int x = 0; x < drawRadius * 2 + 1; x++){ + targetX = x; + for(int y = 0; y < drawRadius * 2 + 1; y++){ + targetY = y; + if(!valid[x][y]){ + found = true; + break; + } + } + if(found){ + break; + } + } + + if(found){ + int currentCellX = cellX - drawRadius + targetX; + int currentCellY = cellY - drawRadius + targetY; + + + if( + currentCellX >= 0 && + currentCellX < commonWorldData.getWorldDiscreteSize() && + currentCellY >= 0 && + currentCellY < commonWorldData.getWorldDiscreteSize() + ){ + if(containsHeightmapAtDiscretePoint(currentCellX, currentCellY)){ + cells[targetX][targetY] = PhysicsDataCell.generateTerrainCell( + currentCellX, + currentCellY, + getHeightmapAtPoint(currentCellX, currentCellY), + getTextureMapAtPoint(currentCellX, currentCellY), + commonWorldData.getDynamicInterpolationRatio() + ); + valid[targetX][targetY] = true; + updateable[targetX][targetY] = false; + hasRequested[targetX][targetY] = false; + hasPhysics[targetX][targetY] = false; + needsPhysics[targetX][targetY] = true; +// if(Math.abs(physicsRadius + 1 - targetX) < physicsRadius && Math.abs(physicsRadius + 1 - targetY) < physicsRadius){ +// needsPhysics[targetX][targetY] = true; +// } + } else { + if(hasRequested[targetX][targetY] == false){ + //client should request macro values from server + Globals.clientConnection.queueOutgoingMessage(TerrainMessage.constructRequestChunkMessage(currentCellX, currentCellY)); + hasRequested[targetX][targetY] = true; + } + } + } else { + valid[targetX][targetY] = true; + updateable[targetX][targetY] = false; + hasRequested[targetX][targetY] = false; + hasPhysics[targetX][targetY] = false; + needsPhysics[targetX][targetY] = true; + } + } + } + + void updateCellModel(){ + int targetX = 0; + int targetY = 0; + boolean found = false; + for(int x = 0; x < drawRadius * 2 + 1; x++){ + targetX = x; + for(int y = 0; y < drawRadius * 2 + 1; y++){ + targetY = y; + if(updateable[x][y]){ + found = true; + break; + } + } + if(found){ + break; + } + } + + if(found){ + int currentCellX = cellX - drawRadius + targetX; + int currentCellY = cellY - drawRadius + targetY; + if( + currentCellX >= 0 && + currentCellX < commonWorldData.getWorldDiscreteSize() && + currentCellY >= 0 && + currentCellY < commonWorldData.getWorldDiscreteSize() + ){ +// if(Math.abs(drawRadius + 1 - targetX) < physicsRadius && Math.abs(drawRadius + 1 - targetY) < physicsRadius){ +// needsPhysics[targetX][targetY] = true; +// } + int dist = (int)Math.sqrt((targetX - drawRadius)*(targetX - drawRadius) + (targetY - drawRadius) * (targetY - drawRadius)); //Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius); + int stride = Math.min(commonWorldData.getDynamicInterpolationRatio()/2, Math.max(1, dist / drawStepdownInterval * drawStepdownValue)); + while(commonWorldData.getDynamicInterpolationRatio() % stride != 0){ + stride = stride + 1; + } + cells[targetX][targetY].generatePhysics(); + } + updateable[targetX][targetY] = false; + } + } + + + public boolean containsInvalidCell(){ +// if(DRAW_CELL_MANAGER_FLAG_UPDATE_DYNAMIC_TERRAIN){ + for(int x = 0;x < drawRadius * 2 + 1; x++){ + for(int y = 0; y < drawRadius * 2 + 1; y++){ + if(!valid[x][y]){ + return true; + } + } + } +// } else if(DRAW_CELL_MANAGER_FLAG_GENERATE_ARENA){ +// return cells[0][0] == null || cells[1][0] == null || cells[0][1] == null | cells[1][1] == null; +// } + return false; + } + + public boolean containsUpdateableCell(){ + for(int x = 0;x < drawRadius * 2 + 1; x++){ + for(int y = 0; y < drawRadius * 2 + 1; y++){ + if(updateable[x][y] && this.generateDrawables){ + return true; + } + } + } + return false; + } + + public boolean containsPhysicsNeedingCell(){ + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + for(int y = 0; y < physicsRadius * 2 + 1; y++){ + if(needsPhysics[x][y]){ + return true; + } + } + } + return false; + } + + public void addPhysicsToCell(){ + int targetX = 0; + int targetY = 0; + boolean found = false; + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + targetX = x; + for(int y = 0; y < physicsRadius * 2 + 1; y++){ + targetY = y; +// System.out.println(x + " <=>w " + y); + if(needsPhysics[x][y]){ + found = true; + break; + } + } + if(found){ + break; + } + } + + if(found){ + int currentCellX = cellX - physicsRadius + targetX; + int currentCellY = cellY - physicsRadius + targetY; + if( + currentCellX >= 0 && + currentCellX < commonWorldData.getWorldDiscreteSize() && + currentCellY >= 0 && + currentCellY < commonWorldData.getWorldDiscreteSize() + ){ +// if(Math.abs(drawRadius + 1 - targetX) < physicsRadius && Math.abs(drawRadius + 1 - targetY) < physicsRadius){ +// needsPhysics[targetX][targetY] = true; +// } +// int dist = (int)Math.sqrt((targetX - drawRadius)*(targetX - drawRadius) + (targetY - drawRadius) * (targetY - drawRadius)); //Math.abs(targetX - drawRadius) * Math.abs(targetY - drawRadius); +// int stride = Math.min(clientWorldData.getDynamicInterpolationRatio()/2, Math.max(1, dist / drawStepdownInterval * drawStepdownValue)); +// while(clientWorldData.getDynamicInterpolationRatio() % stride != 0){ +// stride = stride + 1; +// } +// if(cells[targetX][targetY + drawRadius] != null){ + // System.out.println(targetX + " - " + targetY); + cells[targetX + drawRadius - physicsRadius][targetY + drawRadius - physicsRadius].generatePhysics(); +// } else { +// System.out.println("Current cell is null: " + currentCellX + " - " + currentCellY); +// } + } + needsPhysics[targetX][targetY] = false; + hasPhysics[targetX][targetY] = true; + } + } + + + public void shiftChunksNegX(){ + //retire old graphics + for(int y = 0; y < drawRadius * 2 + 1; y++){ + if(cells[drawRadius * 2][y] != null){ + cells[drawRadius * 2][y].retireCell(); + } + } + //shift draw array + for(int x = drawRadius * 2; x > 0; x--){ + for(int y = 0; y < drawRadius * 2 + 1; y++){ + cells[x][y] = cells[x-1][y]; + updateable[x][y] = true; + hasRequested[x][y] = hasRequested[x-1][y]; + } + } + //invalidate edge of draw array + for(int y = 0; y < drawRadius * 2 + 1; y++){ + valid[0][y] = false; + hasRequested[0][y] = false; + } + //retire physics of cells + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + if(hasPhysics[x][physicsRadius * 2]){ + if(cells[x + drawRadius - physicsRadius][physicsRadius * 2 + drawRadius - physicsRadius] != null){ + cells[x + drawRadius - physicsRadius][physicsRadius * 2 + drawRadius - physicsRadius].destroyPhysics(); + } + } + } + //shift physics array + for(int x = physicsRadius * 2; x > 0; x--){ + for(int y = 0; y < physicsRadius * 2 + 1; y++){ + needsPhysics[x][y] = needsPhysics[x-1][y]; + hasPhysics[x][y] = hasPhysics[x-1][y]; + } + } + //invalidate edge of physics array + for(int y = 0; y < physicsRadius * 2 + 1; y++){ + needsPhysics[0][y] = true; + hasPhysics[0][y] = false; + } + } + + public void shiftChunksPosX(){ + //retire old graphics + for(int y = 0; y < drawRadius * 2 + 1; y++){ + if(cells[0][y] != null){ + cells[0][y].retireCell(); + } + } + //shift draw array + for(int x = 0; x < drawRadius * 2; x++){ + for(int y = 0; y < drawRadius * 2 + 1; y++){ + cells[x][y] = cells[x+1][y]; + updateable[x][y] = true; + hasRequested[x][y] = hasRequested[x+1][y]; + } + } + //invalidate edge of draw array + for(int y = 0; y < drawRadius * 2 + 1; y++){ + valid[drawRadius * 2][y] = false; + hasRequested[drawRadius * 2][y] = false; + } + //retire physics of cells + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + if(hasPhysics[x][physicsRadius * 2]){ + if(cells[x + drawRadius - physicsRadius][physicsRadius * 2 + drawRadius - physicsRadius] != null){ + cells[x + drawRadius - physicsRadius][physicsRadius * 2 + drawRadius - physicsRadius].destroyPhysics(); + } + } + } + //shift physics array + for(int x = 0; x < physicsRadius * 2; x++){ + for(int y = 0; y < physicsRadius * 2 + 1; y++){ + needsPhysics[x][y] = needsPhysics[x+1][y]; + hasPhysics[x][y] = hasPhysics[x+1][y]; + } + } + //invalidate edge of physics array + for(int y = 0; y < physicsRadius * 2 + 1; y++){ + needsPhysics[physicsRadius * 2][y] = true; + hasPhysics[physicsRadius * 2][y] = false; + } + } + + public void shiftChunksNegY(){ + //retire cells + for(int x = 0; x < drawRadius * 2 + 1; x++){ + if(cells[x][drawRadius * 2] != null){ + cells[x][drawRadius * 2].retireCell(); + } + } + //shift draw array + for(int x = 0; x < drawRadius * 2 + 1; x++){ + for(int y = drawRadius * 2; y > 0; y--){ + cells[x][y] = cells[x][y-1]; + updateable[x][y] = true; + hasRequested[x][y] = hasRequested[x][y-1]; + } + } + //invalidate edge of draw array + for(int x = 0; x < drawRadius * 2 + 1; x++){ + valid[x][0] = false; + hasRequested[x][0] = false; + } + //retire physics of cells + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + if(hasPhysics[x][physicsRadius * 2]){ + if(cells[x + drawRadius - physicsRadius][physicsRadius * 2 + drawRadius - physicsRadius] != null){ + cells[x + drawRadius - physicsRadius][physicsRadius * 2 + drawRadius - physicsRadius].destroyPhysics(); + } + } + } + //shift physics array + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + for(int y = physicsRadius * 2; y > 0; y--){ + needsPhysics[x][y] = needsPhysics[x][y-1]; + hasPhysics[x][y] = hasPhysics[x][y-1]; + } + } + //invalidate edge of physics array + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + needsPhysics[x][0] = true; + hasPhysics[x][0] = false; + } + } + + public void shiftChunksPosY(){ + //retire old graphics + for(int x = 0; x < drawRadius * 2 + 1; x++){ + if(cells[x][0] != null){ + cells[x][0].retireCell(); + } + } + //shift draw array + for(int x = 0; x < drawRadius * 2 + 1; x++){ + for(int y = 0; y < drawRadius * 2; y++){ + cells[x][y] = cells[x][y+1]; + updateable[x][y] = true; + hasRequested[x][y] = hasRequested[x][y+1]; + } + } + //invalidate edge of draw array + for(int x = 0; x < drawRadius * 2 + 1; x++){ + valid[x][drawRadius * 2] = false; + hasRequested[x][drawRadius * 2] = false; + } + //retire physics of cells + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + if(hasPhysics[x][0]){ + if(cells[x + drawRadius - physicsRadius][0 + drawRadius - physicsRadius] != null){ + cells[x + drawRadius - physicsRadius][0 + drawRadius - physicsRadius].destroyPhysics(); + } + } + } + //shift physics array + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + for(int y = 0; y < physicsRadius * 2; y++){ + needsPhysics[x][y] = needsPhysics[x][y+1]; + hasPhysics[x][y] = hasPhysics[x][y+1]; + } + } + //invalidate edge of physics array + for(int x = 0; x < physicsRadius * 2 + 1; x++){ + needsPhysics[x][physicsRadius * 2] = true; + hasPhysics[x][physicsRadius * 2] = false; + } + } + + + public int transformRealSpaceToCellSpace(double input){ + return (int)(input / commonWorldData.getDynamicInterpolationRatio()); + } + + + public void invalidateAllCells(){ + for(int x = 0; x < drawRadius * 2 + 1; x++){ + for(int y = 0; y < drawRadius * 2 + 1; y++){ + valid[x][y] = false; + } + } + } + + public void calculateDeltas(Vector3d oldPosition, Vector3d newPosition){ +// if(DRAW_CELL_MANAGER_FLAG_UPDATE_DYNAMIC_TERRAIN){ + if(transformRealSpaceToCellSpace(newPosition.x()) < transformRealSpaceToCellSpace(oldPosition.x())){ + shiftChunksNegX(); + setCellX(transformRealSpaceToCellSpace(newPosition.x())); + setCellY(transformRealSpaceToCellSpace(newPosition.z())); + } else if(transformRealSpaceToCellSpace(newPosition.x()) > transformRealSpaceToCellSpace(oldPosition.x())){ + shiftChunksPosX(); + setCellX(transformRealSpaceToCellSpace(newPosition.x())); + setCellY(transformRealSpaceToCellSpace(newPosition.z())); + } + + if(transformRealSpaceToCellSpace(newPosition.z()) < transformRealSpaceToCellSpace(oldPosition.z())){ + shiftChunksNegY(); + setCellX(transformRealSpaceToCellSpace(newPosition.x())); + setCellY(transformRealSpaceToCellSpace(newPosition.z())); + } else if(transformRealSpaceToCellSpace(newPosition.z()) > transformRealSpaceToCellSpace(oldPosition.z())){ + shiftChunksPosY(); + setCellX(transformRealSpaceToCellSpace(newPosition.x())); + setCellY(transformRealSpaceToCellSpace(newPosition.z())); + } +// } + } + + public void update(){ + if(update){ +// if(DRAW_CELL_MANAGER_FLAG_UPDATE_DYNAMIC_TERRAIN){ + if(containsInvalidCell()){ + updateInvalidCell(); + } else if(containsUpdateableCell()){ + updateCellModel(); + } else if(containsPhysicsNeedingCell()){ + addPhysicsToCell(); + } + } +// } else if(DRAW_CELL_MANAGER_FLAG_GENERATE_ARENA){ +// if(cells[0][0] == null){ +// int arenaChunkWidth = 100; +// cells[0][0] = new DrawCell( +// new float[arenaChunkWidth + 1][arenaChunkWidth + 1], +// arenaChunkWidth + 1, +// 0, +// 0, +// arenaChunkWidth, +// program +// ); +// cells[0][0].generateDrawableEntity(1); +// } else if(cells[0][1] == null){ +// int arenaChunkWidth = 100; +// cells[0][1] = new DrawCell( +// new float[arenaChunkWidth + 1][arenaChunkWidth + 1], +// arenaChunkWidth + 1, +// 0, +// 1, +// arenaChunkWidth, +// program +// ); +// cells[0][1].generateDrawableEntity(1); +// } else if(cells[1][0] == null){ +// int arenaChunkWidth = 100; +// cells[1][0] = new DrawCell( +// new float[arenaChunkWidth + 1][arenaChunkWidth + 1], +// arenaChunkWidth + 1, +// 1, +// 0, +// arenaChunkWidth, +// program +// ); +// cells[1][0].generateDrawableEntity(1); +// } else if(cells[1][1] == null){ +// int arenaChunkWidth = 100; +// cells[1][1] = new DrawCell( +// new float[arenaChunkWidth + 1][arenaChunkWidth + 1], +// arenaChunkWidth + 1, +// 1, +// 1, +// arenaChunkWidth, +// program +// ); +// cells[1][1].generateDrawableEntity(1); +// } +// } + } + +// public float getElevationAtRealPoint(float realPointX, float realPointY){ +//// if(DRAW_CELL_MANAGER_FLAG_UPDATE_DYNAMIC_TERRAIN){ +// return terrainManager.getHeightAtPosition(realPointX, realPointY); +//// } +//// if(DRAW_CELL_MANAGER_FLAG_GENERATE_ARENA){ +//// return 0; +//// } +//// return 0; +// } + + + public boolean canValidateCell(){ + boolean rVal = false; + return rVal; + } + + public boolean coordsInPhysicsSpace(int worldX, int worldY){ + return worldX <= cellX + physicsRadius && worldX >= cellX - physicsRadius && worldY <= cellY + physicsRadius && worldY >= cellY - physicsRadius; + } + + public void setGenerateDrawables(boolean generate){ + this.generateDrawables = generate; + } + + boolean containsHeightmapAtDiscretePoint(int currentCellX, int currentCellY){ + if(Globals.clientTerrainManager != null){ + return Globals.clientTerrainManager.containsHeightmapAtDiscretePoint(currentCellX, currentCellY); + } + return true; + } + + float[][] getHeightmapAtPoint(int currentCellX, int currentCellY){ + if(Globals.clientTerrainManager != null){ + return Globals.clientTerrainManager.getHeightmapAtPoint(currentCellX, currentCellY); + } + return Globals.serverTerrainManager.getChunk(currentCellX, currentCellY).getHeightMap(); + } + + float[][] getTextureMapAtPoint(int currentCellX, int currentCellY){ + if(Globals.clientTerrainManager != null){ + return Globals.clientTerrainManager.getTextureMapAtPoint(currentCellX,currentCellY); + } else { + //hacky fix to +2 to this, I think the interpolation ratio was different for server/client data + //now that we're merging/ambiguous within this class, it's out of bounds-ing unless I +2 + //TODO: investigate + float[][] rVal = new float[commonWorldData.getDynamicInterpolationRatio() + 2][commonWorldData.getDynamicInterpolationRatio() + 2]; + rVal[1][1] = 1; + rVal[2][1] = 1; + rVal[3][1] = 1; + rVal[4][1] = 1; + rVal[5][1] = 1; + rVal[5][2] = 1; + rVal[6][1] = 1; + rVal[6][2] = 1; + return rVal; + } + } +} diff --git a/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java b/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java new file mode 100644 index 00000000..1952278c --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/physics/PhysicsDataCell.java @@ -0,0 +1,94 @@ +package electrosphere.server.datacell.physics; + +import electrosphere.collision.dispatch.CollisionObject; +import electrosphere.dynamics.RigidBody; +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; +import electrosphere.entity.EntityDataStrings; +import electrosphere.entity.EntityUtils; +import electrosphere.game.collision.PhysicsUtils; +import electrosphere.game.collision.collidable.Collidable; +import electrosphere.game.terrain.processing.TerrainInterpolator; +import electrosphere.logger.LoggerInterface; +import electrosphere.renderer.Mesh; +import electrosphere.renderer.Model; +import electrosphere.renderer.ModelUtils; +import electrosphere.renderer.RenderUtils; +import electrosphere.renderer.ShaderProgram; +import electrosphere.renderer.actor.ActorTextureMask; +import electrosphere.renderer.texture.Texture; +import electrosphere.server.datacell.Realm; +import electrosphere.util.Utilities; + +import java.util.LinkedList; +import java.util.List; + +import org.joml.Quaternionf; +import org.joml.Vector3f; + +/** + * + * @author satellite + */ +public class PhysicsDataCell { + int cellX; + int cellZ; + + float[][] heightmap; + float[][] texturemap; + + int dynamicInterpolationRatio; + + Entity physicsEntity; + + CollisionObject physicsObject; + + + PhysicsDataCell(){ + + } + + + public static PhysicsDataCell generateTerrainCell( + int cellX, + int cellZ, + float[][] heightmap, + float[][] texturemap, + int dynamicInterpolationRatio + ){ + PhysicsDataCell rVal = new PhysicsDataCell(); + rVal.cellX = cellX; + rVal.cellZ = cellZ; + rVal.dynamicInterpolationRatio = dynamicInterpolationRatio; + rVal.heightmap = heightmap; + return rVal; + } + + /** + * Retires a physics data cell + */ + public void retireCell(){ + EntityUtils.cleanUpEntity(physicsEntity); + } + + public void generatePhysics(){ + //if the entity hasn't already been created for some reason, need to create it + if(physicsEntity == null){ + physicsEntity = EntityCreationUtils.createClientSpatialEntity(); + physicsEntity.putData(EntityDataStrings.TERRAIN_IS_TERRAIN, true); + EntityUtils.getPosition(physicsEntity).set(new Vector3f(cellX * dynamicInterpolationRatio, 0.0f, cellZ * dynamicInterpolationRatio)); + } + //then actually perform the attach + physicsObject = PhysicsUtils.attachTerrainRigidBody(physicsEntity,heightmap,true); + Realm realm = Globals.realmManager.getEntityRealm(physicsEntity); + realm.getCollisionEngine().registerPhysicsEntity(physicsEntity); + } + + public void destroyPhysics(){ + Realm realm = Globals.realmManager.getEntityRealm(physicsEntity); + realm.getCollisionEngine().deregisterCollidableEntity(physicsEntity); + realm.getCollisionEngine().deregisterRigidBody((RigidBody)physicsObject); + } + +} diff --git a/src/main/java/electrosphere/server/datacell/utils/DataCellSearchUtils.java b/src/main/java/electrosphere/server/datacell/utils/DataCellSearchUtils.java new file mode 100644 index 00000000..2a7b5aee --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/utils/DataCellSearchUtils.java @@ -0,0 +1,38 @@ +package electrosphere.server.datacell.utils; + +import java.util.Set; + +import org.joml.Vector3d; + +import electrosphere.engine.Globals; +import electrosphere.entity.Entity; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.ServerDataCell; + +/** + * Provides utilities for searching cells for groups of entities + */ +public class DataCellSearchUtils { + + /** + * Gets the data cell the entity is inside of + * @param entity The entity + * @return The data cell the entitiy is inside of, or null if it isn't inside a data cell for some reason + */ + public static ServerDataCell getEntityDataCell(Entity entity){ + return Globals.realmManager.getEntityRealm(entity).getEntityDataCellMapper().getEntityDataCell(entity); + } + + /** + * Searches around the cell containing location (radius 1 extra cell including corners) for all entities under the specified tag + * @param location The real (non-world) location to search + * @param tag The tag to search for + * @return All entities with the tag in the search area + */ + public static Set getEntitiesWithTagAroundLocation(Realm realm, Vector3d location, String tag){ + ServerDataCell cell = realm.getDataCellManager().getDataCellAtPoint(location); + return cell.getScene().getEntitiesWithTag(tag); + } + + +} diff --git a/src/main/java/electrosphere/server/datacell/utils/EntityLookupUtils.java b/src/main/java/electrosphere/server/datacell/utils/EntityLookupUtils.java new file mode 100644 index 00000000..cac84bc7 --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/utils/EntityLookupUtils.java @@ -0,0 +1,51 @@ +package electrosphere.server.datacell.utils; + +import java.util.HashMap; +import java.util.Map; + +import electrosphere.entity.Entity; + +/** + * Utilities for looking up entities + * Broke the id<->entity logic out from realm manager as it didn't make sense there + */ +public class EntityLookupUtils { + + //map of all entities by their ID + static Map idToEntityMap = new HashMap(); + + /** + * Registers the entity on the server side so that it can be looked up by id + * @param entity The entity to register + */ + public static void registerServerEntity(Entity entity){ + idToEntityMap.put(entity.getId(), entity); + } + + /** + * Gets the entity with a given id + * @param id The id + * @return The entity if it exists, null otherwise + */ + public static Entity getEntityById(int id){ + return idToEntityMap.get(id); + } + + /** + * Removes an entity from registration with the server + * @param entity The entity to remove + */ + public static void removeEntity(Entity entity){ + idToEntityMap.remove(entity.getId()); + } + + /** + * Returns whether this entity was created by the server or the client + * @param entity The entity to test + * @return True if the entity was created by the server, false otherwise + */ + public static boolean isServerEntity(Entity entity){ + return idToEntityMap.containsKey(entity.getId()); + } + +} diff --git a/src/main/java/electrosphere/server/datacell/utils/ServerBehaviorTreeUtils.java b/src/main/java/electrosphere/server/datacell/utils/ServerBehaviorTreeUtils.java new file mode 100644 index 00000000..9dc9fa32 --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/utils/ServerBehaviorTreeUtils.java @@ -0,0 +1,81 @@ +package electrosphere.server.datacell.utils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import electrosphere.entity.Entity; +import electrosphere.entity.state.BehaviorTree; +import electrosphere.server.datacell.ServerDataCell; + +/** + * Abstracting away behavior tree management so that it can be a "register btree to entity" and forget about it type deal + * + * Note, there is no universal, hard coupling of an entity to a behavior tree outside of this class. + * TODO?: Should maybe consider refactoring that mechanism into a dedicated manager or something. + */ +public class ServerBehaviorTreeUtils { + + static Map> entityBTreeMap = new HashMap>(); + + /** + * Tracks behavior trees attached to this entity + * @param entity + */ + public static void registerEntity(Entity entity){ + entityBTreeMap.put(entity, new HashSet()); + } + + /** + * Stops tracking behavior trees attached to this entity + * @param entity + */ + public static void deregisterEntity(Entity entity){ + Set trees = entityBTreeMap.remove(entity); + ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity); + for(BehaviorTree tree : trees){ + currentCell.getScene().registerBehaviorTree(tree); + } + } + + /** + * Registers a behavior tree to an entity + * @param entity The entity + * @param behaviorTree The behavior tree + */ + public static void attachBTreeToEntity(Entity entity, BehaviorTree behaviorTree){ + entityBTreeMap.get(entity).add(behaviorTree); + //register to cell + ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity); + currentCell.getScene().registerBehaviorTree(behaviorTree); + } + + /** + * Removes the behavior tree from the entity + * @param entity The entity + * @param behaviorTree The behavior tree + */ + public static void detatchBTreeFromEntity(Entity entity, BehaviorTree behaviorTree){ + entityBTreeMap.get(entity).remove(behaviorTree); + //deregister from cell + ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity); + currentCell.getScene().registerBehaviorTree(behaviorTree); + } + + + /** + * Updates the server data cell that all entity trees are registered to + * @param entity The entity + * @param oldCell The cell the entity used to inhabit + */ + public static void updateCell(Entity entity, ServerDataCell oldCell){ + Set trees = entityBTreeMap.get(entity); + ServerDataCell newCell = DataCellSearchUtils.getEntityDataCell(entity); + for(BehaviorTree tree : trees){ + oldCell.getScene().deregisterBehaviorTree(tree); + newCell.getScene().registerBehaviorTree(tree); + } + } + +} diff --git a/src/main/java/electrosphere/server/datacell/utils/ServerEntityTagUtils.java b/src/main/java/electrosphere/server/datacell/utils/ServerEntityTagUtils.java new file mode 100644 index 00000000..d6696a39 --- /dev/null +++ b/src/main/java/electrosphere/server/datacell/utils/ServerEntityTagUtils.java @@ -0,0 +1,31 @@ +package electrosphere.server.datacell.utils; + +import electrosphere.entity.Entity; +import electrosphere.server.datacell.ServerDataCell; + +/** + * + */ +public class ServerEntityTagUtils { + + /** + * Attachs a tag to an entity. !!WARNING!! This depends on the entity already being in a datacell. + * @param entity The entity + * @param tag The tag + */ + public static void attachTagToEntity(Entity entity, String tag){ + ServerDataCell cell = DataCellSearchUtils.getEntityDataCell(entity); + cell.getScene().registerEntityToTag(entity, tag); + } + + /** + * Removes a tag from an entity. !!WARNING!! This depends on the entity already being in a datacell. + * @param entity The entity + * @param tag The tag + */ + public static void removeTagFromEntity(Entity entity, String tag){ + ServerDataCell cell = DataCellSearchUtils.getEntityDataCell(entity); + cell.getScene().removeEntityFromTag(entity, tag); + } + +} diff --git a/src/main/java/electrosphere/server/pathfinding/NavMeshPathfinder.java b/src/main/java/electrosphere/server/pathfinding/NavMeshPathfinder.java index 3274f63d..f54368af 100644 --- a/src/main/java/electrosphere/server/pathfinding/NavMeshPathfinder.java +++ b/src/main/java/electrosphere/server/pathfinding/NavMeshPathfinder.java @@ -1,6 +1,7 @@ package electrosphere.server.pathfinding; import electrosphere.entity.Entity; +import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityUtils; import electrosphere.server.pathfinding.navmesh.NavCube; import electrosphere.server.pathfinding.navmesh.NavMesh; @@ -70,12 +71,14 @@ public class NavMeshPathfinder { //TODO: return path while(currentItem != null){ if(currentItem.node == endNode){ - Entity waypoint = EntityUtils.spawnDrawableEntity("Models/waypoint1.fbx"); + Entity waypoint = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(waypoint, "Models/waypoint1.fbx"); // System.out.println(end); EntityUtils.getPosition(waypoint).set(end.x,end.y + 1,end.z); EntityUtils.getRotation(waypoint).rotateLocalX(-(float)Math.PI/2.0f); } else { - Entity waypoint = EntityUtils.spawnDrawableEntity("Models/waypoint1.fbx"); + Entity waypoint = EntityCreationUtils.createClientSpatialEntity(); + EntityCreationUtils.makeEntityDrawable(waypoint, "Models/waypoint1.fbx"); // System.out.println(currentItem.currentPos); EntityUtils.getPosition(waypoint).set(currentItem.currentPos.x,currentItem.currentPos.y + 1,currentItem.currentPos.z); EntityUtils.getRotation(waypoint).rotateLocalX(-(float)Math.PI/2.0f); diff --git a/src/main/java/electrosphere/server/poseactor/PoseActor.java b/src/main/java/electrosphere/server/poseactor/PoseActor.java new file mode 100644 index 00000000..9974e153 --- /dev/null +++ b/src/main/java/electrosphere/server/poseactor/PoseActor.java @@ -0,0 +1,295 @@ +package electrosphere.server.poseactor; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; + +import org.joml.AxisAngle4f; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; +import org.joml.Vector4f; + +import electrosphere.engine.Globals; +import electrosphere.renderer.Bone; +import electrosphere.renderer.actor.ActorAnimationMask; +import electrosphere.renderer.actor.ActorBoneRotator; +import electrosphere.renderer.actor.ActorStaticMorph; +import electrosphere.renderer.actor.ActorStaticMorph.StaticMorphTransforms; + +/** + * An actor that references a posemodel + */ +public class PoseActor { + + String modelPath; + //scalar on the speed of animation playback + float animationScalar = 1.0f; + //priority queue of animations to play. Allows masking a higher priority animation over a lower priority one. + PriorityQueue animationQueue = new PriorityQueue(); + //bone rotation map. Used to apply rotator functionality to bones (think hair, cloth, and camera rotation on looking) + Map boneRotators = new HashMap(); + //static morph used to apply an initial, static modification to the layout of bones in the pose model + ActorStaticMorph staticMorph; + + + /** + * Constructor + * @param modelPath The path on disk of this poseactor's posemodel + */ + public PoseActor(String modelPath){ + this.modelPath = modelPath; + } + + + //Used to keep track of which animations have completed and therefore should be removed + //Separate variable so no concurrent modification to anim lists/maps + List toRemoveMasks = new LinkedList(); + /** + * Increments time of all currently played animations + * @param deltaTime + */ + public void incrementAnimationTime(double deltaTime){ + toRemoveMasks.clear(); + for(ActorAnimationMask mask : animationQueue){ + mask.setTime(mask.getTime() + deltaTime * animationScalar); + if(mask.getTime() > mask.getDuration()){ + toRemoveMasks.add(mask); + } + } + for(ActorAnimationMask mask : toRemoveMasks){ + animationQueue.remove(mask); + } + } + + /** + * Gets the current time of a given animation + * @param animationName The animation name + * @return The current time of the animation if it exists, -1.0f otherwise + */ + public double getAnimationTime(String animationName){ + for(ActorAnimationMask mask : animationQueue){ + if(mask.getAnimationName().contains(animationName)){ + return mask.getTime(); + } + } + return -1.0f; + } + + /** + * Gets whether the animation is currently playing or not + * @param animationName The animation name + * @return True if the animation is playing, false otherwise + */ + public boolean isPlayingAnimation(String animationName){ + for(ActorAnimationMask mask : animationQueue){ + if(mask.getAnimationName().contains(animationName)){ + return true; + } + } + return false; + } + + /** + * Gets whether the actor is playing ANY animation + * @return True if the actor is playing ANY animation, false otherwise + */ + public boolean isPlayingAnimation(){ + return animationQueue.size() > 0; + } + + /** + * Stops playing a specific animation + * @param animationName The name of the animation to stop playing + */ + public void stopAnimation(String animationName){ + List toRemove = new LinkedList(); + for(ActorAnimationMask mask : animationQueue){ + if(mask.getAnimationName().contains(animationName)){ + toRemove.add(mask); + } + } + for(ActorAnimationMask mask : toRemove){ + animationQueue.remove(mask); + } + } + + /** + * Adds an animation to play at a specific priority level + * @param animationName The name of the animation to play + * @param priority The priority to play the animation at + */ + public void playAnimation(String animationName, int priority){ + PoseModel model = Globals.assetManager.fetchPoseModel(modelPath); + if(model != null){ + double length = model.getAnimation(animationName).duration; + ActorAnimationMask animMask = new ActorAnimationMask(priority, animationName, 0, length); + for(Bone bone : model.bones){ + animMask.addBone(bone.boneID); + } + toRemoveMasks.clear(); + for(ActorAnimationMask currentMask : animationQueue){ + if(currentMask.getPriority() == animMask.getPriority()){ + toRemoveMasks.add(currentMask); + break; + } + } + for(ActorAnimationMask currentMask : toRemoveMasks){ + animationQueue.remove(currentMask); + } + animationQueue.add(animMask); + } + } + + /** + * Play an animation with a mask that makes the animation only apply to specific bones + * @param animationName The name of the animation + * @param priority The priority to play it at + * @param boneMask The mask of bones that the animation should apply to + */ + public void playAnimationWithMask(String animationName, int priority, List boneMask){ + PoseModel model = Globals.assetManager.fetchPoseModel(modelPath); + if(model != null){ + double length = model.getAnimation(animationName).duration; + ActorAnimationMask animMask = new ActorAnimationMask(priority, animationName, 0, length, boneMask); + toRemoveMasks.clear(); + for(ActorAnimationMask currentMask : animationQueue){ + if(currentMask.getPriority() == animMask.getPriority()){ + toRemoveMasks.add(currentMask); + break; + } + } + for(ActorAnimationMask currentMask : toRemoveMasks){ + animationQueue.remove(currentMask); + } + animationQueue.add(animMask); + } + } + + /** + * Applies an animation mask to the PoseModel + * @param model The posemodel to apply the mask to + */ + void applyAnimationMasks(PoseModel model){ + List bonesUsed = new LinkedList(); + List currentAnimationMask = new LinkedList(); + for(ActorAnimationMask mask : animationQueue){ + currentAnimationMask.clear(); + for(String currentBone : mask.getBones()){ + if(!bonesUsed.contains(currentBone)){ + bonesUsed.add(currentBone); + currentAnimationMask.add(currentBone); + } + } + model.applyAnimationMask(mask.getAnimationName(), mask.getTime(), currentAnimationMask); + } + } + + /** + * Calculates all node transforms for the PoseModel based on bone rotators and the static morph of this PoseActor + * @param model The PoseModel to calculate transforms for + */ + void calculateNodeTransforms(PoseModel model){ + model.updateNodeTransform(boneRotators,staticMorph); + } + + /** + * Sets the animation scalar + * @param animationScalar The new animation scalar value + */ + public void setAnimationScalar(float animationScalar) { + this.animationScalar = animationScalar; + } + + /** + * Sets the static morph of this pose actor + * @param staticMorph The static morph to set + */ + public void setStaticMorph(ActorStaticMorph staticMorph){ + this.staticMorph = staticMorph; + } + + + /** + * Adds a bone rotator to the pose actor + * @param boneRotator The bone rotator + */ + public void addBoneRotator(String boneName, ActorBoneRotator boneRotator){ + boneRotators.put(boneName, boneRotator); + } + + /** + * Gets a specific bone rotator by name + * @param bone The name of the bone + * @return The bone rotator for that bone + */ + public ActorBoneRotator getBoneRotator(String bone){ + return boneRotators.get(bone); + } + + /** + * Gets the current rotation of a specific bone + * @param boneName The name of the bone + * @return The rotation quaternion of the bone + */ + public Quaternionf getBoneRotation(String boneName){ + Quaternionf rVal = new Quaternionf(); + PoseModel model = Globals.assetManager.fetchPoseModel(modelPath); + if(model != null){ + applyAnimationMasks(model); + calculateNodeTransforms(model); + Bone currentBone = model.boneMap.get(boneName); + if(currentBone != null){ + AxisAngle4f axisAngle = new AxisAngle4f(); + currentBone.final_transform.getRotation(axisAngle); + Quaternionf rotation = new Quaternionf(axisAngle); + rVal.set(rotation); + } + } + return rVal; + } + + /** + * Gets the position of a bone currently + * @param boneName + * @return + */ + public Vector3f getBonePosition(String boneName){ + Vector3f rVal = new Vector3f(); + PoseModel model = Globals.assetManager.fetchPoseModel(modelPath); + if(model != null){ + applyAnimationMasks(model); + calculateNodeTransforms(model); + // if(animation != null){ + // model.playAnimation(animation); + // model.incrementTime(animationTime); + // model.updateNodeTransform(); + Bone currentBone = model.boneMap.get(boneName); + if(currentBone != null){ + Vector4f result = currentBone.final_transform.transform(new Matrix4f(currentBone.inverseBindPoseMatrix).invert().transform(new Vector4f(rVal.x,rVal.y,rVal.z,1))); +// currentBone.inverseBindPoseMatrix + rVal.x = result.x; + rVal.y = result.y; + rVal.z = result.z; + } + // } + } + return rVal; + } + + /** + * Checks if the pose model is loaded + * @return True if the pose model is loaded, false otherwise + */ + public boolean modelIsLoaded(){ + PoseModel model = Globals.assetManager.fetchPoseModel(modelPath); + if(model != null){ + return true; + } else { + return false; + } + } + +} diff --git a/src/main/java/electrosphere/server/poseactor/PoseActorUtils.java b/src/main/java/electrosphere/server/poseactor/PoseActorUtils.java new file mode 100644 index 00000000..aa492359 --- /dev/null +++ b/src/main/java/electrosphere/server/poseactor/PoseActorUtils.java @@ -0,0 +1,19 @@ +package electrosphere.server.poseactor; + +import electrosphere.entity.Entity; +import electrosphere.entity.EntityUtils; + +public class PoseActorUtils { + + + public static void applyBlenderTransformer(Entity actorEntity){ + PoseActor entityActor = EntityUtils.getPoseActor(actorEntity); + entityActor.setAnimationScalar(60f); //should be the value of the fps i think + EntityUtils.getScale(actorEntity).set(0.005f); + } + + public static void applyBlenderRotation(Entity actorEntity){ + EntityUtils.getRotation(actorEntity).rotateLocalX((float)-Math.PI/2); + } + +} diff --git a/src/main/java/electrosphere/server/poseactor/PoseModel.java b/src/main/java/electrosphere/server/poseactor/PoseModel.java new file mode 100644 index 00000000..78abc39d --- /dev/null +++ b/src/main/java/electrosphere/server/poseactor/PoseModel.java @@ -0,0 +1,203 @@ +package electrosphere.server.poseactor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.joml.Matrix4f; +import org.lwjgl.PointerBuffer; +import org.lwjgl.assimp.AIAnimation; +import org.lwjgl.assimp.AIBone; +import org.lwjgl.assimp.AIMesh; +import org.lwjgl.assimp.AINode; +import org.lwjgl.assimp.AIScene; + +import electrosphere.engine.Globals; +import electrosphere.logger.LoggerInterface; +import electrosphere.renderer.Bone; +import electrosphere.renderer.actor.ActorBoneRotator; +import electrosphere.renderer.actor.ActorStaticMorph; +import electrosphere.renderer.anim.AnimChannel; +import electrosphere.renderer.anim.AnimNode; +import electrosphere.renderer.anim.Animation; +import electrosphere.renderer.loading.ModelPretransforms; + +/** + * Used server side to load model data for positioning hitboxes based on animations + */ +public class PoseModel { + + List bones; + Map boneMap; + Matrix4f globalInverseTransform; + Map nodeMap; + AnimNode rootAnimNode; + List animations; + Map animMap; + + + /** + * Constructor + * @param path Path on disk to this posemodel + * @param scene The AI Scene parsed from the file on disk + */ + public PoseModel(String path, AIScene scene){ + ModelPretransforms.ModelMetadata modelMetadata = Globals.modelPretransforms.getModel(path); + + bones = new ArrayList(); + boneMap = new HashMap(); + nodeMap = new HashMap(); + animations = new ArrayList(); + animMap = new HashMap(); + + // + //parse bones + // + PointerBuffer meshesBuffer = scene.mMeshes(); + while(meshesBuffer.hasRemaining()){ + AIMesh currentMeshData = AIMesh.createSafe(meshesBuffer.get()); + LoggerInterface.loggerRenderer.DEBUG("mesh name:" + currentMeshData.mName().dataString()); + PointerBuffer boneBuffer = currentMeshData.mBones(); + for(int j = 0; j < currentMeshData.mNumBones(); j++){ + AIBone currentBone = AIBone.createSafe(boneBuffer.get()); + String currentBoneName = currentBone.mName().dataString(); + if(!boneMap.containsKey(currentBoneName)){ + Bone boneObject = new Bone(currentBone); + boneMap.put(currentBoneName, boneObject); + bones.add(boneObject); + } + } + } + + // + //parse animation nodes and form hierarchy + // + AINode rootNode = scene.mRootNode(); + globalInverseTransform = electrosphere.util.Utilities.convertAIMatrix(rootNode.mTransformation()); + rootAnimNode = buildAnimNodeMap(scene.mRootNode(),null); + + // + //load animations + // + int animCount = scene.mNumAnimations(); + PointerBuffer animBuffer = scene.mAnimations(); + animations = new ArrayList(); + animMap = new HashMap(); + for(int i = 0; i < animCount; i++){ + Animation newAnim = new Animation(AIAnimation.create(animBuffer.get(i)), i); + animations.add(newAnim); + animMap.put(newAnim.name,newAnim); + } + } + + + /** + * Applies an animation to a certain set of bones + * @param animationName The name of the animation + * @param time The time in the animation to apply + * @param mask The set of bones to apply the animation to + */ + public void applyAnimationMask(String animationName, double time, List mask){ + Animation animationCurrent = animMap.get(animationName); + if(animationCurrent != null){ + for(String boneName : mask){ + AnimChannel currentChannel = animationCurrent.getChannel(boneName); + Bone currentBone = boneMap.get(currentChannel.getNodeID()); + currentChannel.setTime(time); + // System.out.println(currentChannel + " " + currentBone); + if(currentBone != null){ + // System.out.println("Applying to bone"); + //T * S * R + currentBone.deform = new Matrix4f(); + currentBone.deform.translate(currentChannel.getCurrentPosition()); + currentBone.deform.rotate(currentChannel.getCurrentRotation()); + currentBone.deform.scale(currentChannel.getCurrentScale()); + } + } + } + } + + + /** + * Builds an AnimNode map based on an AINode from assimp + * @param node The AINode from assimp + * @param parent The parent AnimNode if it exists + * @return The AnimNode map relative to this node + */ + public final AnimNode buildAnimNodeMap(AINode node, AnimNode parent){ + AnimNode node_object = new AnimNode(node.mName().dataString(), parent, node); + nodeMap.put(node_object.id, node_object); + if(boneMap.containsKey(node_object.id)){ + node_object.is_bone = true; + } + int num_children = node.mNumChildren(); + for(int i = 0; i < num_children; i++){ + AnimNode temp_child = buildAnimNodeMap(AINode.create(node.mChildren().get(i)),node_object); + node_object.children.add(temp_child); + } + return node_object; + } + + + /** + * Updates node transforms based on bone rotators and static morph + * @param boneRotators The bone rotators + * @param staticMorph The static morph + */ + public void updateNodeTransform(Map boneRotators, ActorStaticMorph staticMorph){ + if(this.rootAnimNode != null){ + updateNodeTransform(this.rootAnimNode,boneRotators,staticMorph); + } + } + + /** + * Internal recursive method behind the public updateNodeTransform + * @param boneRotators The bone rotators + * @param staticMorph The static morph + */ + void updateNodeTransform(AnimNode n, Map boneRotators, ActorStaticMorph staticMorph){ + //grab parent transform if exists + if(n.parent != null){ + n.transform = new Matrix4f(n.parent.transform); + } else { + n.transform = new Matrix4f(); + } + //if this is a bone, calculate the transform for the bone + if(n.is_bone){ + Bone target_bone = boneMap.get(n.id); + n.transform = n.transform.mul(target_bone.deform); + if(boneRotators.containsKey(target_bone.boneID)){ + n.transform.rotate(boneRotators.get(target_bone.boneID).getRotation()); + } + Matrix4f bone_matrix = new Matrix4f(n.transform); + if(staticMorph != null && staticMorph.getBoneTransforms(n.id) != null){ + bone_matrix.mul(staticMorph.getBoneTransforms(n.id).getTransform()); + n.transform.mul(staticMorph.getBoneTransforms(n.id).getTransform()); + } + bone_matrix.mul(target_bone.inverseBindPoseMatrix); + bone_matrix = new Matrix4f(globalInverseTransform).mul(bone_matrix); + target_bone.final_transform = bone_matrix; + } else { + //not a bone, so use transform directly from data + n.transform = n.transform.mul(electrosphere.util.Utilities.convertAIMatrix(n.raw_data.mTransformation())); + } + //update all children accordingly + Iterator node_iterator = n.children.iterator(); + while(node_iterator.hasNext()){ + AnimNode current_node = node_iterator.next(); + updateNodeTransform(current_node,boneRotators,staticMorph); + } + } + + /** + * Gets an animation with a specific name + * @param animName The name of the animation + * @return The animation if it exists, null otherwise + */ + public Animation getAnimation(String animName){ + return animMap.get(animName); + } + +} diff --git a/src/main/java/electrosphere/server/saves/SaveUtils.java b/src/main/java/electrosphere/server/saves/SaveUtils.java index dcd2effe..8a8cc673 100644 --- a/src/main/java/electrosphere/server/saves/SaveUtils.java +++ b/src/main/java/electrosphere/server/saves/SaveUtils.java @@ -6,7 +6,6 @@ import electrosphere.engine.Globals; import electrosphere.game.server.terrain.manager.ServerTerrainManager; import electrosphere.game.server.world.ServerWorldData; import electrosphere.logger.LoggerInterface; -import electrosphere.server.datacell.DataCellManager; import electrosphere.server.db.DatabaseUtils; import electrosphere.util.FileUtils; @@ -106,12 +105,11 @@ public class SaveUtils { return FileUtils.checkFileExists(dirPath); } - public static boolean loadTerrainAndCreateWorldData(){ + public static boolean loadTerrainAndCreateWorldData(String currentSaveName){ Globals.serverTerrainManager = new ServerTerrainManager(2000,50,100,0.0f,0); - SaveUtils.loadTerrainAndDB(Globals.currentSaveName); + SaveUtils.loadTerrainAndDB(currentSaveName); Globals.serverWorldData = ServerWorldData.createGameWorld(Globals.serverTerrainManager); - Globals.dataCellManager = new DataCellManager(Globals.serverWorldData); - Globals.dataCellManager.init(); + Globals.realmManager.createGriddedRealm(Globals.serverWorldData); return true; } diff --git a/src/main/java/electrosphere/server/simulation/MicroSimulation.java b/src/main/java/electrosphere/server/simulation/MicroSimulation.java index e0ea89dd..0619e7dc 100644 --- a/src/main/java/electrosphere/server/simulation/MicroSimulation.java +++ b/src/main/java/electrosphere/server/simulation/MicroSimulation.java @@ -9,13 +9,15 @@ import electrosphere.entity.EntityTags; import electrosphere.entity.EntityUtils; import electrosphere.entity.scene.EntityDescriptor; import electrosphere.entity.state.BehaviorTree; -import electrosphere.entity.state.IdleTree; import electrosphere.entity.state.movement.GroundMovementTree; import electrosphere.entity.state.ParticleTree; import electrosphere.entity.state.attack.AttackTree; -import electrosphere.entity.state.collidable.CollidableTree; +import electrosphere.entity.state.collidable.ClientCollidableTree; +import electrosphere.entity.state.collidable.ServerCollidableTree; import electrosphere.entity.state.gravity.GravityTree; +import electrosphere.entity.state.idle.IdleTree; import electrosphere.entity.types.creature.CreatureUtils; +import electrosphere.entity.types.hitbox.HitboxManager; import electrosphere.entity.types.hitbox.HitboxUtils; import electrosphere.entity.types.item.ItemUtils; import electrosphere.entity.state.life.LifeState; @@ -25,6 +27,7 @@ import electrosphere.entity.types.particle.ParticleUtils; import electrosphere.game.client.targeting.crosshair.Crosshair; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.renderer.actor.Actor; +import electrosphere.server.datacell.ServerDataCell; import java.sql.Time; @@ -43,9 +46,7 @@ public class MicroSimulation { isReady = false; } - public void simulate(){ - //simulate bullet physics engine step - Globals.collisionEngine.simulatePhysics(Main.deltaFrames); + public void simulate(ServerDataCell dataCell, HitboxManager hitboxManager){ //update dynamic entity positions calculated by bullet // Globals.collisionEngine.updateDynamicObjectTransforms(); //list dynamic object positions @@ -53,7 +54,7 @@ public class MicroSimulation { //simulate ai Globals.aiManager.simulate(); //update actor animations - for(Entity currentEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.DRAWABLE)){ + for(Entity currentEntity : dataCell.getScene().getEntitiesWithTag(EntityTags.DRAWABLE)){ //fetch actor Actor currentActor = EntityUtils.getActor(currentEntity); //increment animations @@ -62,55 +63,25 @@ public class MicroSimulation { } } //make items play idle animation - for(Entity item : Globals.entityManager.getEntitiesWithTag(EntityTags.ITEM)){ + for(Entity item : dataCell.getScene().getEntitiesWithTag(EntityTags.ITEM)){ ItemUtils.updateItemActorAnimation(item); } - //simulate creature behavior trees - // for(Entity currentMoveable : Globals.entityManager.getEntitiesWithTag(EntityTags.MOVEABLE)){ - // BehaviorTree behaviorTree = CreatureUtils.getEntityMovementTree(currentMoveable); - // behaviorTree.simulate(Main.deltaFrames); - // } - // //sprint tree - // for(Entity currentSprint : Globals.entityManager.getEntitiesWithTag(EntityTags.SPRINTABLE)){ - // SprintTree sprintTree = CreatureUtils.getSprintTree(currentSprint); - // sprintTree.simulate(Main.deltaFrames); - // } - // //simulate creature gravity trees - // for(Entity currentGravity : Globals.entityManager.getEntitiesWithTag(EntityTags.GRAVITY)){ - // GravityTree gravityTree = (GravityTree)currentGravity.getData(EntityDataStrings.GRAVITY_TREE); - // gravityTree.simulate(Main.deltaFrames); - // } - // //attacker behavior tree - // for(Entity currentAttacker : Globals.entityManager.getEntitiesWithTag(EntityTags.ATTACKER)){ - // AttackTree attackTree = CreatureUtils.getAttackTree(currentAttacker); - // attackTree.simulate(Main.deltaFrames); - // } - // //idle behavior tree - // for(Entity currentIdler : Globals.entityManager.getEntitiesWithTag(EntityTags.CREATURE)){ - // IdleTree idleTree = CreatureUtils.getIdleTree(currentIdler); - // idleTree.simulate(Main.deltaFrames); - // } - // //life state updates - // for(Entity lifeStateEntity : Globals.entityManager.getEntitiesWithTag(EntityTags.LIFE_STATE)){ - // LifeState lifeState = LifeUtils.getLifeState(lifeStateEntity); - // lifeState.simulate(Main.deltaFrames); - // } //particle state updates - for(Entity particle : Globals.entityManager.getEntitiesWithTag(EntityTags.PARTICLE)){ + for(Entity particle : dataCell.getScene().getEntitiesWithTag(EntityTags.PARTICLE)){ // ParticleTree tree = ParticleUtils.getParticleTree(particle); // tree.simulate(Main.deltaFrames); ParticleUtils.makeParticleBillboardFaceCamera(particle); } //update attached entity positions - AttachUtils.updateAttachedEntityPositions(); + AttachUtils.serverUpdateAttachedEntityPositions(dataCell); //update hitbox positions - for(Entity currentHitbox : Globals.hitboxManager.getAllHitboxes()){ - HitboxUtils.updatePosition(currentHitbox); + for(Entity currentHitbox : hitboxManager.getAllHitboxes()){ + HitboxUtils.serverUpdatePosition(currentHitbox); } //collide hitboxes - for(Entity currentHitbox : Globals.hitboxManager.getAllHitboxes()){ + for(Entity currentHitbox : hitboxManager.getAllHitboxes()){ if(isReady){ - HitboxUtils.collideEntities(currentHitbox); + HitboxUtils.serverCollideEntities(currentHitbox); } } //tally collidables and offset position accordingly @@ -124,23 +95,14 @@ public class MicroSimulation { Crosshair.updateTargetCrosshairPosition(); } //simulate behavior trees - Globals.entityManager.simulateBehaviorTrees(Main.deltaFrames); + dataCell.getScene().simulateBehaviorTrees(Main.deltaFrames); //sum collidable impulses - for(Entity collidable : Globals.entityManager.getEntitiesWithTag(EntityTags.COLLIDABLE)){ - CollidableTree.getCollidableTree(collidable).simulate(Main.deltaFrames); + for(Entity collidable : dataCell.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE)){ + ServerCollidableTree.getServerCollidableTree(collidable).simulate(Main.deltaFrames); } - //clear collidable impulse lists - Globals.collisionEngine.clearCollidableImpulseLists(); //delete all client side entities that aren't in visible chunks - if(Globals.RUN_CLIENT){ - Globals.entityManager.clearOutOfBoundsEntities(); - } - //data cell manager update - if(Globals.dataCellManager != null){ - boolean playerHasChangedChunk = Globals.dataCellManager.updatePlayerGroundCellPositions(); - if(playerHasChangedChunk){ - Globals.dataCellManager.unloadPlayerlessChunks(); - } + if(Globals.clientEntityCullingManager != null){ + Globals.clientEntityCullingManager.clearOutOfBoundsEntities(); } } diff --git a/src/test/java/entity/SpawningCreaturesTest.java b/src/test/java/entity/SpawningCreaturesTest.java index 99c29346..65a6ec62 100644 --- a/src/test/java/entity/SpawningCreaturesTest.java +++ b/src/test/java/entity/SpawningCreaturesTest.java @@ -8,6 +8,7 @@ import electrosphere.engine.Globals; import electrosphere.engine.Main; import electrosphere.entity.types.creature.CreatureUtils; import electrosphere.net.NetUtils; +import electrosphere.server.datacell.Realm; import testutils.TestEntityUtils; public class SpawningCreaturesTest { @@ -36,8 +37,9 @@ public class SpawningCreaturesTest { @Test public void testSpawnMultipleCreatures(){ + Realm realm = Globals.realmManager.getRealms().iterator().next(); for(int i = 0; i < 100; i++){ - CreatureUtils.spawnBasicCreature("human", null); + CreatureUtils.serverSpawnBasicCreature(realm, new Vector3d(0,0,0), "human", null); } Main.mainLoop(1); assert TestEntityUtils.numberOfEntitiesInBox(new Vector3d(-1,-1,-1),new Vector3d(1,1,1)) == 100; diff --git a/src/test/java/testutils/TestEntityUtils.java b/src/test/java/testutils/TestEntityUtils.java index 71e9750f..80f8c0eb 100644 --- a/src/test/java/testutils/TestEntityUtils.java +++ b/src/test/java/testutils/TestEntityUtils.java @@ -5,6 +5,9 @@ import org.joml.Vector3d; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; +import electrosphere.server.datacell.Realm; +import electrosphere.server.datacell.ServerDataCell; +import electrosphere.server.datacell.utils.DataCellSearchUtils; public class TestEntityUtils { @@ -24,7 +27,9 @@ public class TestEntityUtils { int accumulator = 0; - for(Entity entity : Globals.entityManager.getEntityList()){ + Realm realm = Globals.realmManager.getRealms().iterator().next(); + ServerDataCell dataCell = realm.getDataCellManager().getDataCellAtPoint(new Vector3d(minX,minY,minZ)); + for(Entity entity : dataCell.getScene().getEntityList()){ if(EntityUtils.getPosition(entity) != null){ Vector3d position = EntityUtils.getPosition(entity); if(