package electrosphere.entity.state.gravity; import electrosphere.entity.EntityDataStrings; import electrosphere.net.synchronization.BehaviorTreeIdEnums; import electrosphere.net.parser.net.message.SynchronizationMessage; import electrosphere.server.datacell.utils.DataCellSearchUtils; import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import org.joml.Quaterniond; import org.joml.Quaternionf; import org.joml.Vector3d; import org.joml.Vector3f; import org.ode4j.ode.DBody; import electrosphere.collision.collidable.Collidable; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityUtils; import electrosphere.entity.state.BehaviorTree; import electrosphere.entity.state.collidable.Impulse; import electrosphere.entity.state.collidable.ServerCollidableTree; import electrosphere.entity.state.gravity.ClientGravityTree.GravityTreeState; import electrosphere.entity.state.movement.ServerFallTree; import electrosphere.entity.state.movement.ServerJumpTree; import electrosphere.net.parser.net.message.EntityMessage; import electrosphere.net.synchronization.annotation.SyncedField; import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree; import electrosphere.server.datacell.Realm; @SynchronizedBehaviorTree(name = "serverGravity", isServer = true, correspondingTree="gravity") /** * Tree for making the entity fall if there's nothing underneath it */ public class ServerGravityTree implements BehaviorTree { @SyncedField GravityTreeState state; Entity parent; int frameCurrent = 0; int fallFrame = 1; float gravityVelocity = 0; float gravityAccel = 0.0007f; DBody body; Collidable collidable; List networkMessageQueue = new CopyOnWriteArrayList(); private ServerGravityTree(Entity e, Collidable collidable, DBody 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; // } /** *

Automatically generated

*

* Gets state. *

*/ public GravityTreeState getState(){ return state; } public void start(){ //TODO: check if can start moving setState(GravityTreeState.ACTIVE); if(state == GravityTreeState.NOT_ACTIVE){ frameCurrent = 0; } } public void interrupt(){ setState(GravityTreeState.NOT_ACTIVE); } public void stop(){ setState(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); Quaterniond rotation = EntityUtils.getRotation(parent); Vector3f newPosition; 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()){ setState(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,"gravity")); } 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; } /** *

Automatically generated

*

* Sets state and handles the synchronization logic for it. *

* @param state The value to set state to. */ public void setState(GravityTreeState state){ this.state = state; int value = ClientGravityTree.getGravityTreeStateEnumAsShort(state); DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(SynchronizationMessage.constructUpdateClientStateMessage(parent.getId(), 1, 1, value)); } /** *

(initially) Automatically generated

*

More parameters can be safely added to this method

*

* Attaches this tree to the entity. *

* @param entity The entity to attach to * @param tree The behavior tree to attach */ public static ServerGravityTree attachTree(Entity parent, Collidable collidable, DBody body, int fallFrame){ ServerGravityTree rVal = new ServerGravityTree(parent,collidable,body,fallFrame); //put manual code here (setting params, etc) //!!WARNING!! from here below should not be touched //This was generated automatically to properly alert various systems that the btree exists and should be tracked ServerBehaviorTreeUtils.attachBTreeToEntity(parent, rVal); parent.putData(EntityDataStrings.TREE_SERVERGRAVITY, rVal); Globals.entityValueTrackingService.attachTreeToEntity(parent, BehaviorTreeIdEnums.BTREE_SERVERGRAVITY_ID); return rVal; } /** *

Automatically generated

*

* Detatches this tree from the entity. *

* @param entity The entity to detach to * @param tree The behavior tree to detach */ public static void detachTree(Entity entity, BehaviorTree tree){ Globals.entityValueTrackingService.detatchTreeFromEntity(entity, BehaviorTreeIdEnums.BTREE_SERVERGRAVITY_ID); } /** *

* Gets the ServerGravityTree of the entity *

* @param entity the entity * @return The ServerGravityTree */ public static ServerGravityTree getServerGravityTree(Entity entity){ return (ServerGravityTree)entity.getData(EntityDataStrings.TREE_SERVERGRAVITY); } }