Renderer/src/main/java/electrosphere/entity/state/gravity/ServerGravityTree.java
2024-02-25 11:49:17 -05:00

300 lines
12 KiB
Java

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<EntityMessage> networkMessageQueue = new CopyOnWriteArrayList<EntityMessage>();
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;
// }
/**
* <p> Automatically generated </p>
* <p>
* Gets state.
* </p>
*/
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;
}
/**
* <p> Automatically generated </p>
* <p>
* Sets state and handles the synchronization logic for it.
* </p>
* @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));
}
/**
* <p> (initially) Automatically generated </p>
* <p> More parameters can be safely added to this method</p>
* <p>
* Attaches this tree to the entity.
* </p>
* @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;
}
/**
* <p> Automatically generated </p>
* <p>
* Detatches this tree from the entity.
* </p>
* @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);
}
/**
* <p>
* Gets the ServerGravityTree of the entity
* </p>
* @param entity the entity
* @return The ServerGravityTree
*/
public static ServerGravityTree getServerGravityTree(Entity entity){
return (ServerGravityTree)entity.getData(EntityDataStrings.TREE_SERVERGRAVITY);
}
}