client-server physics synchronization
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
All checks were successful
studiorailgun/Renderer/pipeline/head This commit looks good
This commit is contained in:
parent
1cc4924c3b
commit
ee15dd2366
@ -11,9 +11,6 @@
|
||||
- Block SFX
|
||||
|
||||
+ rearchitecture
|
||||
Ability to synchronize state of synchronized variables on client joining scene
|
||||
ie, send currentBlockVariant when client connects
|
||||
this is probably going to involve massive netcode arch to send all synchronized variables for each entity
|
||||
|
||||
+ fix the vibes
|
||||
Attack animation feels slow
|
||||
|
||||
@ -535,6 +535,7 @@ Ability to serialize/deserialize a creature with equipped items
|
||||
|
||||
(08/11/2024)
|
||||
Sending initial synchronized state on player connect to chunk
|
||||
Pass at client-server physics synchronization
|
||||
|
||||
|
||||
# TODO
|
||||
|
||||
@ -49,6 +49,54 @@
|
||||
"name" : "rotationW",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "linVelX",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "linVelY",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "linVelZ",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "angVelX",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "angVelY",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "angVelZ",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "linForceX",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "linForceY",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "linForceZ",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "angForceX",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "angForceY",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "angForceZ",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
},
|
||||
{
|
||||
"name" : "yaw",
|
||||
"type" : "FIXED_DOUBLE"
|
||||
@ -263,6 +311,33 @@
|
||||
"yaw",
|
||||
"pitch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"messageName" : "syncPhysics",
|
||||
"description" : "Synchronizes server physics state to client",
|
||||
"data" : [
|
||||
"entityID",
|
||||
"time",
|
||||
"positionX",
|
||||
"positionY",
|
||||
"positionZ",
|
||||
"rotationX",
|
||||
"rotationY",
|
||||
"rotationZ",
|
||||
"rotationW",
|
||||
"linVelX",
|
||||
"linVelY",
|
||||
"linVelZ",
|
||||
"angVelX",
|
||||
"angVelY",
|
||||
"angVelZ",
|
||||
"linForceX",
|
||||
"linForceY",
|
||||
"linForceZ",
|
||||
"angForceX",
|
||||
"angForceY",
|
||||
"angForceZ"
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package electrosphere.client.sim;
|
||||
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3f;
|
||||
|
||||
import electrosphere.client.fluid.manager.ClientFluidManager;
|
||||
import electrosphere.client.instancing.InstanceUpdater;
|
||||
|
||||
@ -1,31 +1,26 @@
|
||||
package electrosphere.collision;
|
||||
|
||||
import static org.ode4j.ode.OdeConstants.dContactBounce;
|
||||
import static org.ode4j.ode.OdeConstants.dContactSoftCFM;
|
||||
import static org.ode4j.ode.OdeConstants.dInfinity;
|
||||
// import static org.ode4j.ode.OdeConstants.dContactBounce;
|
||||
// import static org.ode4j.ode.OdeConstants.dContactSoftCFM;
|
||||
// import static org.ode4j.ode.OdeConstants.dInfinity;
|
||||
import static org.ode4j.ode.OdeHelper.areConnectedExcluding;
|
||||
import static org.ode4j.ode.OdeMath.dCalcVectorLengthSquare3;
|
||||
import static org.ode4j.ode.OdeMath.dSubtractVectors3;
|
||||
import static org.ode4j.ode.internal.Common.dRecip;
|
||||
// import static org.ode4j.ode.OdeMath.dCalcVectorLengthSquare3;
|
||||
// import static org.ode4j.ode.OdeMath.dSubtractVectors3;
|
||||
// import static org.ode4j.ode.internal.Common.dRecip;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import org.joml.Matrix4d;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3f;
|
||||
import org.joml.Vector4d;
|
||||
import org.ode4j.math.DMatrix3;
|
||||
import org.ode4j.math.DVector3;
|
||||
import org.ode4j.math.DVector3C;
|
||||
import org.ode4j.math.DVector4;
|
||||
import org.ode4j.ode.DBody;
|
||||
import org.ode4j.ode.DBox;
|
||||
import org.ode4j.ode.DCapsule;
|
||||
@ -740,6 +735,27 @@ public class CollisionEngine {
|
||||
spaceLock.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes the data on a body
|
||||
* @param body The body
|
||||
* @param position The position
|
||||
* @param rotation The rotation
|
||||
* @param linearVel The linear velocity
|
||||
* @param angularVel The angular velocity
|
||||
* @param linearForce The linear force
|
||||
* @param angularForce The angular force
|
||||
*/
|
||||
protected void synchronizeData(DBody body, Vector3d position, Quaterniond rotation, Vector3d linearVel, Vector3d angularVel, Vector3d linearForce, Vector3d angularForce){
|
||||
spaceLock.acquireUninterruptibly();
|
||||
body.setPosition(position.x, position.y, position.z);
|
||||
body.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
|
||||
body.setLinearVel(PhysicsUtils.jomlVecToOdeVec(linearVel));
|
||||
body.setAngularVel(PhysicsUtils.jomlVecToOdeVec(angularVel));
|
||||
body.setForce(PhysicsUtils.jomlVecToOdeVec(linearForce));
|
||||
body.setTorque(PhysicsUtils.jomlVecToOdeVec(angularForce));
|
||||
spaceLock.release();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transform on a body
|
||||
* @param body The body
|
||||
|
||||
@ -28,29 +28,6 @@ public class CollisionWorldData {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* IF SERVER, RETURN HEIGHT
|
||||
* IF CLIENT:
|
||||
* IF HAS DATA,
|
||||
* RETURN HEIGHT
|
||||
* IF DOES NOT HAVE DATA,
|
||||
* RETURN 0
|
||||
* @param position
|
||||
* @return
|
||||
*/
|
||||
// public double getElevationAtPoint(Vector3d position){
|
||||
// if(clientWorldData != null){
|
||||
// if(clientTerrainManager.containsHeightmapAtRealPoint(position.x, position.z)){
|
||||
// return clientTerrainManager.getHeightAtPosition(position.x, position.z);
|
||||
// } else {
|
||||
// return 0;
|
||||
// }
|
||||
// } else {
|
||||
// return serverTerrainManager.getHeightAtPosition(position.x, position.z);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
public Vector3f getWorldBoundMin(){
|
||||
if(clientWorldData != null){
|
||||
return clientWorldData.getWorldBoundMin();
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
package electrosphere.collision;
|
||||
|
||||
import org.joml.Matrix4d;
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
import org.joml.Vector3f;
|
||||
import org.ode4j.ode.DBody;
|
||||
import org.ode4j.ode.DGeom;
|
||||
import org.ode4j.ode.DTriMesh;
|
||||
@ -17,6 +15,8 @@ import electrosphere.entity.EntityTags;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.state.collidable.ClientCollidableTree;
|
||||
import electrosphere.entity.state.collidable.ServerCollidableTree;
|
||||
import electrosphere.entity.state.physicssync.ClientPhysicsSyncTree;
|
||||
import electrosphere.entity.state.physicssync.ServerPhysicsSyncTree;
|
||||
import electrosphere.entity.types.terrain.TerrainChunkData;
|
||||
import electrosphere.game.data.collidable.CollidableTemplate;
|
||||
import electrosphere.server.datacell.Realm;
|
||||
@ -33,11 +33,9 @@ public class PhysicsEntityUtils {
|
||||
* @param physicsTemplate The collidable template
|
||||
*/
|
||||
public static void clientAttachCollidableTemplate(Entity rVal, CollidableTemplate physicsTemplate){
|
||||
DBody rigidBody;
|
||||
DBody rigidBody = null;
|
||||
Collidable collidable;
|
||||
float mass = 1.0f;
|
||||
Matrix4f inertiaTensor;
|
||||
Vector3f scale;
|
||||
switch(physicsTemplate.getType()){
|
||||
case "CYLINDER": {
|
||||
rigidBody = CollisionBodyCreation.createCylinderBody(
|
||||
@ -63,7 +61,6 @@ public class PhysicsEntityUtils {
|
||||
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
|
||||
rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree);
|
||||
|
||||
scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3());
|
||||
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
|
||||
|
||||
Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
|
||||
@ -88,13 +85,16 @@ public class PhysicsEntityUtils {
|
||||
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
|
||||
rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree);
|
||||
|
||||
scale = new Vector3f(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3());
|
||||
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
|
||||
|
||||
Globals.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
|
||||
Globals.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
|
||||
} break;
|
||||
}
|
||||
//if we successfully attached the body, add a sync tree
|
||||
if(rigidBody != null){
|
||||
ClientPhysicsSyncTree.attachTree(rVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -108,8 +108,6 @@ public class PhysicsEntityUtils {
|
||||
DBody rigidBody = null;
|
||||
Collidable collidable;
|
||||
float mass = 1.0f;
|
||||
Matrix4f inertiaTensor;
|
||||
Vector3f scale;
|
||||
switch(physicsTemplate.getType()){
|
||||
case "CYLINDER": {
|
||||
rigidBody = CollisionBodyCreation.createCylinderBody(
|
||||
@ -136,7 +134,6 @@ public class PhysicsEntityUtils {
|
||||
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);
|
||||
|
||||
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
|
||||
@ -157,13 +154,16 @@ public class PhysicsEntityUtils {
|
||||
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);
|
||||
|
||||
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable);
|
||||
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
|
||||
} break;
|
||||
}
|
||||
//if we successfully attached the body, add a sync tree
|
||||
if(rigidBody != null){
|
||||
ServerPhysicsSyncTree.attachTree(rVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -78,6 +78,20 @@ public class PhysicsUtils {
|
||||
collisionEngine.setBodyTransform(body, position, rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes the data on a body
|
||||
* @param body The body
|
||||
* @param position The position
|
||||
* @param rotation The rotation
|
||||
* @param linearVel The linear velocity
|
||||
* @param angularVel The angular velocity
|
||||
* @param linearForce The linear force
|
||||
* @param angularForce The angular force
|
||||
*/
|
||||
public static void synchronizeData(CollisionEngine collisionEngine, DBody body, Vector3d position, Quaterniond rotation, Vector3d linearVel, Vector3d angularVel, Vector3d linearForce, Vector3d angularForce){
|
||||
collisionEngine.synchronizeData(body, position, rotation, linearVel, angularVel, linearForce, angularForce);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the position + rotation + scale of a body
|
||||
|
||||
@ -300,6 +300,12 @@ public class EntityDataStrings {
|
||||
*/
|
||||
public static final String TREE_SERVERPLAYERVIEWDIR = "treeServerPlayerViewDir";
|
||||
|
||||
/**
|
||||
* Physics synchronization
|
||||
*/
|
||||
public static final String TREE_SERVERPHYSICSSYNCTREE = "treeServerPhysicsSyncTree";
|
||||
public static final String TREE_CLIENTPHYSICSSYNCTREE = "treeClientPhysicsSyncTree";
|
||||
|
||||
/*
|
||||
Entity categories
|
||||
*/
|
||||
|
||||
@ -3,12 +3,15 @@ package electrosphere.entity;
|
||||
import org.joml.Vector3d;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.state.hitbox.HitboxCollectionState;
|
||||
import electrosphere.entity.types.collision.CollisionObjUtils;
|
||||
import electrosphere.net.parser.net.message.EntityMessage;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Entity utilities specifically for the server side
|
||||
@ -88,6 +91,11 @@ public class ServerEntityUtils {
|
||||
//if the entity had physics, remove them from the world
|
||||
realm.getCollisionEngine().destroyEntityThatHasPhysics(entity);
|
||||
}
|
||||
HitboxCollectionState.destroyHitboxState(entity);
|
||||
ServerBehaviorTreeUtils.deregisterEntity(entity);
|
||||
Globals.realmManager.removeEntity(entity);
|
||||
EntityLookupUtils.removeEntity(entity);
|
||||
//deregister all behavior trees
|
||||
EntityUtils.cleanUpEntity(entity);
|
||||
}
|
||||
|
||||
|
||||
@ -75,7 +75,6 @@ public class SceneLoader {
|
||||
realm = Globals.realmManager.createRealm();
|
||||
} break;
|
||||
}
|
||||
ServerDataCell rVal = realm.createNewCell();
|
||||
//spawn initial entities
|
||||
for(EntityDescriptor descriptor : file.getEntities()){
|
||||
//spawn entity somehow
|
||||
@ -85,14 +84,12 @@ public class SceneLoader {
|
||||
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: {
|
||||
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: {
|
||||
@ -100,7 +97,6 @@ public class SceneLoader {
|
||||
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);
|
||||
} break;
|
||||
default:
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
@ -6,6 +6,7 @@ import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.ServerEntityUtils;
|
||||
import electrosphere.entity.state.equip.ClientEquipState;
|
||||
import electrosphere.entity.state.equip.ServerEquipState;
|
||||
import electrosphere.entity.state.gravity.GravityUtils;
|
||||
@ -113,10 +114,10 @@ public class InventoryUtils {
|
||||
//send message
|
||||
controllerPlayer.addMessage(InventoryMessage.constructaddItemToInventoryMessage(inventoryItem.getId(), ItemUtils.getType(inventoryItem)));
|
||||
}
|
||||
//destroy the item that was left over
|
||||
ItemUtils.serverDestroyInWorldItem(item);
|
||||
//alert script engine
|
||||
ServerScriptUtils.fireSignalOnEntity(creature, "itemPickup", item.getId(), inventoryItem.getId());
|
||||
//destroy the item that was left over
|
||||
ServerEntityUtils.destroyEntity(item);
|
||||
return inventoryItem;
|
||||
}
|
||||
return null;
|
||||
@ -223,8 +224,8 @@ public class InventoryUtils {
|
||||
// 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);
|
||||
NetworkMessage unequipMessage = InventoryMessage.constructserverCommandUnequipItemMessage(creature.getId(), inventorySlot);
|
||||
dataCell.broadcastNetworkMessage(unequipMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -244,8 +245,8 @@ public class InventoryUtils {
|
||||
//
|
||||
//compose item into in-world entity
|
||||
Entity inWorldItem = ItemUtils.serverSpawnBasicItem(realm,dropSpot,ItemUtils.getType(item));
|
||||
//delete in container item
|
||||
ItemUtils.destroyInInventoryItem(item);
|
||||
//destroy the entity on server side
|
||||
ServerEntityUtils.destroyEntity(item);
|
||||
//activate gravity
|
||||
GravityUtils.serverAttemptActivateGravity(inWorldItem);
|
||||
}
|
||||
|
||||
@ -239,7 +239,6 @@ public class ClientGroundMovementTree implements BehaviorTree {
|
||||
}
|
||||
Quaterniond movementQuaternion = new Quaterniond().rotationTo(MathUtils.getOriginVector(), new Vector3d(facingVector.x,0,facingVector.z)).normalize();
|
||||
Quaterniond rotation = EntityUtils.getRotation(parent);
|
||||
rotation.set(movementQuaternion);
|
||||
|
||||
//parse attached network messages
|
||||
for(EntityMessage message : networkMessageQueue){
|
||||
@ -295,6 +294,9 @@ public class ClientGroundMovementTree implements BehaviorTree {
|
||||
//state machine
|
||||
switch(state){
|
||||
case STARTUP: {
|
||||
//update rotation
|
||||
rotation.set(movementQuaternion);
|
||||
//play animation
|
||||
String animationToPlay = determineCorrectAnimation();
|
||||
if(entityActor != null){
|
||||
if(!entityActor.isPlayingAnimation(animationToPlay)){
|
||||
@ -329,6 +331,9 @@ public class ClientGroundMovementTree implements BehaviorTree {
|
||||
GravityUtils.clientAttemptActivateGravity(parent);
|
||||
} break;
|
||||
case MOVE: {
|
||||
//update rotation
|
||||
rotation.set(movementQuaternion);
|
||||
//play animation
|
||||
String animationToPlay = determineCorrectAnimation();
|
||||
if(entityActor != null){
|
||||
if(!entityActor.isPlayingAnimation(animationToPlay)){
|
||||
@ -359,6 +364,8 @@ public class ClientGroundMovementTree implements BehaviorTree {
|
||||
GravityUtils.clientAttemptActivateGravity(parent);
|
||||
} break;
|
||||
case SLOWDOWN: {
|
||||
//update rotation
|
||||
rotation.set(movementQuaternion);
|
||||
//run slowdown code
|
||||
String animationToPlay = determineCorrectAnimation();
|
||||
if(entityActor != null){
|
||||
|
||||
@ -0,0 +1,118 @@
|
||||
package electrosphere.entity.state.physicssync;
|
||||
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
import org.ode4j.ode.DBody;
|
||||
|
||||
import electrosphere.collision.PhysicsEntityUtils;
|
||||
import electrosphere.collision.PhysicsUtils;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.btree.BehaviorTree;
|
||||
import electrosphere.net.parser.net.message.EntityMessage;
|
||||
|
||||
/**
|
||||
* Receives synchronization data from the client
|
||||
*/
|
||||
public class ClientPhysicsSyncTree implements BehaviorTree {
|
||||
|
||||
//The parent entity for the tree
|
||||
Entity parent;
|
||||
|
||||
//The most recent message received from the client
|
||||
EntityMessage latestMessage = null;
|
||||
|
||||
//checks if the message has been pushed to the physics engine or not
|
||||
boolean hasPushesMessage = true;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param parent
|
||||
* @param params
|
||||
*/
|
||||
private ClientPhysicsSyncTree(Entity parent, Object ... params){
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulate(float deltaTime) {
|
||||
if(!hasPushesMessage && latestMessage != null){
|
||||
this.hasPushesMessage = true;
|
||||
Vector3d position = new Vector3d(latestMessage.getpositionX(),latestMessage.getpositionY(),latestMessage.getpositionZ());
|
||||
Quaterniond rotationFromServer = new Quaterniond(latestMessage.getrotationX(),latestMessage.getrotationY(),latestMessage.getrotationZ(),latestMessage.getrotationW());
|
||||
Vector3d linearVelocity = new Vector3d(latestMessage.getlinVelX(), latestMessage.getlinVelY(), latestMessage.getlinVelZ());
|
||||
Vector3d angularVelocity = new Vector3d();
|
||||
Vector3d linearForce = new Vector3d(latestMessage.getlinForceX(), latestMessage.getlinForceY(), latestMessage.getlinForceZ());
|
||||
Vector3d angularForce = new Vector3d();
|
||||
DBody body = PhysicsEntityUtils.getDBody(parent);
|
||||
EntityUtils.getPosition(parent).set(position);
|
||||
EntityUtils.getRotation(parent).set(rotationFromServer);
|
||||
PhysicsUtils.synchronizeData(Globals.clientSceneWrapper.getCollisionEngine(), body, position, rotationFromServer, linearVelocity, angularVelocity, linearForce, angularForce);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the message for this sync tree
|
||||
* @param syncMessage The synchronization message received from the server
|
||||
*/
|
||||
public void setMessage(EntityMessage syncMessage){
|
||||
if(this.latestMessage == null){
|
||||
this.latestMessage = syncMessage;
|
||||
this.hasPushesMessage = false;
|
||||
} else if(this.latestMessage.gettime() < syncMessage.gettime()){
|
||||
this.latestMessage = syncMessage;
|
||||
this.hasPushesMessage = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p> (initially) Automatically generated </p>
|
||||
* <p>
|
||||
* Attaches this tree to the entity.
|
||||
* </p>
|
||||
* @param entity The entity to attach to
|
||||
* @param tree The behavior tree to attach
|
||||
* @param params Optional parameters that will be provided to the constructor
|
||||
*/
|
||||
public static ClientPhysicsSyncTree attachTree(Entity parent, Object ... params){
|
||||
ClientPhysicsSyncTree rVal = new ClientPhysicsSyncTree(parent,params);
|
||||
//!!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
|
||||
parent.putData(EntityDataStrings.TREE_CLIENTPHYSICSSYNCTREE, rVal);
|
||||
Globals.clientSceneWrapper.getScene().registerBehaviorTree(rVal);
|
||||
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){
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the entity has a physics sync tree
|
||||
* @param entity The entity to check
|
||||
* @return True if the entity contains a physics sync tree, false otherwise
|
||||
*/
|
||||
public static boolean hasTree(Entity entity){
|
||||
return entity.containsKey(EntityDataStrings.TREE_CLIENTPHYSICSSYNCTREE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client physics sync tree on the entity
|
||||
* @param entity The entity
|
||||
* @return The tree if it exists, null otherwise
|
||||
*/
|
||||
public static ClientPhysicsSyncTree getTree(Entity entity){
|
||||
return (ClientPhysicsSyncTree)entity.getData(EntityDataStrings.TREE_CLIENTPHYSICSSYNCTREE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,129 @@
|
||||
package electrosphere.entity.state.physicssync;
|
||||
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
import org.ode4j.ode.DBody;
|
||||
|
||||
import electrosphere.collision.PhysicsEntityUtils;
|
||||
import electrosphere.collision.PhysicsUtils;
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.entity.EntityDataStrings;
|
||||
import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.btree.BehaviorTree;
|
||||
import electrosphere.net.parser.net.message.EntityMessage;
|
||||
import electrosphere.server.datacell.utils.DataCellSearchUtils;
|
||||
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
|
||||
|
||||
/**
|
||||
* Synchronized physics state to client
|
||||
*/
|
||||
public class ServerPhysicsSyncTree implements BehaviorTree {
|
||||
|
||||
//The parent entity for the tree
|
||||
Entity parent;
|
||||
|
||||
//the last sent transforms
|
||||
Vector3d lastSentPosition = new Vector3d();
|
||||
Quaterniond lastSentRotation = new Quaterniond();
|
||||
|
||||
//threshold of position/rotation difference after which a sync packet is sent to client
|
||||
static final double UPDATE_THRESHOLD = 0.01;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param parent
|
||||
* @param params
|
||||
*/
|
||||
private ServerPhysicsSyncTree(Entity parent, Object ... params){
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulate(float deltaTime) {
|
||||
Vector3d position = EntityUtils.getPosition(parent);
|
||||
Quaterniond rotation = EntityUtils.getRotation(parent);
|
||||
DBody body = PhysicsEntityUtils.getDBody(parent);
|
||||
//velocities
|
||||
Vector3d linearVel = PhysicsUtils.odeVecToJomlVec(body.getLinearVel());
|
||||
Vector3d angularVel = PhysicsUtils.odeVecToJomlVec(body.getAngularVel());
|
||||
//forces
|
||||
Vector3d linearForce = PhysicsUtils.odeVecToJomlVec(body.getForce());
|
||||
Vector3d angularForce = PhysicsUtils.odeVecToJomlVec(body.getTorque());
|
||||
if(position.distance(lastSentPosition) > UPDATE_THRESHOLD || 1.0 - rotation.dot(lastSentRotation) > UPDATE_THRESHOLD){
|
||||
lastSentPosition.set(position);
|
||||
lastSentRotation.set(rotation);
|
||||
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
|
||||
EntityMessage.constructsyncPhysicsMessage(
|
||||
parent.getId(),
|
||||
Globals.timekeeper.getNumberOfSimFramesElapsed(),
|
||||
position.x,
|
||||
position.y,
|
||||
position.z,
|
||||
rotation.x,
|
||||
rotation.y,
|
||||
rotation.z,
|
||||
rotation.w,
|
||||
linearVel.x,
|
||||
linearVel.y,
|
||||
linearVel.z,
|
||||
angularVel.x,
|
||||
angularVel.y,
|
||||
angularVel.z,
|
||||
linearForce.x,
|
||||
linearForce.y,
|
||||
linearForce.z,
|
||||
angularForce.x,
|
||||
angularForce.y,
|
||||
angularForce.z
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Attaches this tree to the entity.
|
||||
* </p>
|
||||
* @param entity The entity to attach to
|
||||
* @param tree The behavior tree to attach
|
||||
* @param params Optional parameters that will be provided to the constructor
|
||||
*/
|
||||
public static ServerPhysicsSyncTree attachTree(Entity parent, Object ... params){
|
||||
ServerPhysicsSyncTree rVal = new ServerPhysicsSyncTree(parent,params);
|
||||
//!!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_SERVERPHYSICSSYNCTREE, rVal);
|
||||
return rVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* <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){
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the entity has a physics sync tree
|
||||
* @param entity The entity to check
|
||||
* @return True if the entity contains a physics sync tree, false otherwise
|
||||
*/
|
||||
public static boolean hasTree(Entity entity){
|
||||
return entity.containsKey(EntityDataStrings.TREE_SERVERPHYSICSSYNCTREE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server physics sync tree on the entity
|
||||
* @param entity The entity
|
||||
* @return The tree if it exists, null otherwise
|
||||
*/
|
||||
public static ServerPhysicsSyncTree getTree(Entity entity){
|
||||
return (ServerPhysicsSyncTree)entity.getData(EntityDataStrings.TREE_SERVERPHYSICSSYNCTREE);
|
||||
}
|
||||
|
||||
}
|
||||
@ -659,6 +659,12 @@ public class CreatureUtils {
|
||||
//The server initialization logic checks what type of entity this is, if this function is called prior to its type being stored
|
||||
//the server will not be able to synchronize it properly.
|
||||
ServerEntityUtils.initiallyPositionEntity(realm,rVal,position);
|
||||
|
||||
//error checking
|
||||
if(Globals.realmManager.getEntityRealm(rVal) == null){
|
||||
LoggerInterface.loggerEngine.ERROR(new IllegalStateException("Created creature without it being assigned to a realm!"));
|
||||
}
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ import electrosphere.game.data.item.type.EquipData;
|
||||
import electrosphere.game.data.item.type.EquipWhitelist;
|
||||
import electrosphere.game.data.item.type.Item;
|
||||
import electrosphere.game.data.item.type.WeaponData;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.net.parser.net.message.EntityMessage;
|
||||
import electrosphere.net.parser.net.message.NetworkMessage;
|
||||
import electrosphere.net.server.player.Player;
|
||||
@ -198,6 +199,11 @@ public class ItemUtils {
|
||||
//the server will not be able to synchronize it properly.
|
||||
ServerEntityUtils.initiallyPositionEntity(realm,rVal,correctedPosition);
|
||||
|
||||
//error checking
|
||||
if(Globals.realmManager.getEntityRealm(rVal) == null){
|
||||
LoggerInterface.loggerEngine.ERROR(new IllegalStateException("Created item without it being assigned to a realm!"));
|
||||
}
|
||||
|
||||
return rVal;
|
||||
}
|
||||
|
||||
@ -427,32 +433,10 @@ public class ItemUtils {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
if(itemRealm != null){
|
||||
itemRealm.getCollisionEngine().destroyEntityThatHasPhysics(item);
|
||||
//destroy hitboxes
|
||||
HitboxCollectionState.destroyHitboxState(item);
|
||||
}
|
||||
//destroy graphics
|
||||
EntityUtils.cleanUpEntity(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getWeaponClass(Entity item){
|
||||
return (String)item.getData(EntityDataStrings.ITEM_WEAPON_CLASS);
|
||||
}
|
||||
|
||||
public static void destroyInInventoryItem(Entity item){
|
||||
EntityUtils.cleanUpEntity(item);
|
||||
}
|
||||
|
||||
public static String getItemIcon(Entity item){
|
||||
return (String)item.getData(EntityDataStrings.ITEM_ICON);
|
||||
}
|
||||
|
||||
@ -451,18 +451,20 @@ public class ImGuiEntityMacros {
|
||||
if(PhysicsEntityUtils.getDBody(detailViewEntity) != null){
|
||||
DBody physicsBody = PhysicsEntityUtils.getDBody(detailViewEntity);
|
||||
if(physicsBody != null){
|
||||
ImGui.text("Position (Server): " + EntityUtils.getPosition(detailViewEntity));
|
||||
ImGui.text("Rotation (Server): " + EntityUtils.getRotation(detailViewEntity));
|
||||
ImGui.text("Velocity (Server): " + physicsBody.getLinearVel());
|
||||
ImGui.text("Force (Server): " + physicsBody.getForce());
|
||||
ImGui.text("Move Vector (Server): " + CreatureUtils.getFacingVector(detailViewEntity));
|
||||
ImGui.text("Velocity (Server): " + CreatureUtils.getVelocity(detailViewEntity));
|
||||
ImGui.text("Position: " + EntityUtils.getPosition(detailViewEntity));
|
||||
ImGui.text("Rotation: " + EntityUtils.getRotation(detailViewEntity));
|
||||
ImGui.text("Velocity: " + physicsBody.getLinearVel());
|
||||
ImGui.text("Force: " + physicsBody.getForce());
|
||||
ImGui.text("Angular Velocity: " + physicsBody.getAngularVel());
|
||||
ImGui.text("Torque: " + physicsBody.getTorque());
|
||||
ImGui.text("Move Vector: " + CreatureUtils.getFacingVector(detailViewEntity));
|
||||
ImGui.text("Velocity: " + CreatureUtils.getVelocity(detailViewEntity));
|
||||
}
|
||||
//synchronized data
|
||||
if(Globals.clientSceneWrapper.getScene().getEntityFromId(detailViewEntity.getId()) != null){
|
||||
//detailViewEntity is a client entity
|
||||
//get server entity
|
||||
int serverIdForClientEntity = Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId());
|
||||
int serverIdForClientEntity = Globals .clientSceneWrapper.mapClientToServerId(detailViewEntity.getId());
|
||||
Entity serverEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
|
||||
DBody serverPhysicsBody = PhysicsEntityUtils.getDBody(serverEntity);
|
||||
if(serverPhysicsBody != null){
|
||||
@ -472,6 +474,8 @@ public class ImGuiEntityMacros {
|
||||
ImGui.text("Rotation (Server): " + EntityUtils.getRotation(serverEntity));
|
||||
ImGui.text("Velocity (Server): " + serverPhysicsBody.getLinearVel());
|
||||
ImGui.text("Force (Server): " + serverPhysicsBody.getForce());
|
||||
ImGui.text("Angular Velocity: " + serverPhysicsBody.getAngularVel());
|
||||
ImGui.text("Torque: " + serverPhysicsBody.getTorque());
|
||||
ImGui.text("Move Vector (Server): "+ CreatureUtils.getFacingVector(serverEntity));
|
||||
ImGui.text("Velocity (Server): " + CreatureUtils.getVelocity(serverEntity));
|
||||
}
|
||||
@ -484,12 +488,14 @@ public class ImGuiEntityMacros {
|
||||
if(clientPhysicsBody != null){
|
||||
ImGui.newLine();
|
||||
ImGui.text("Linked client entity:");
|
||||
ImGui.text("Position (Server): " + EntityUtils.getPosition(clientEntity));
|
||||
ImGui.text("Rotation (Server): " + EntityUtils.getRotation(clientEntity));
|
||||
ImGui.text("Velocity (Server): " + clientPhysicsBody.getLinearVel());
|
||||
ImGui.text("Force (Server): " + clientPhysicsBody.getForce());
|
||||
ImGui.text("Move Vector (Server): " + CreatureUtils.getFacingVector(clientEntity));
|
||||
ImGui.text("Velocity (Server): " + CreatureUtils.getVelocity(clientEntity));
|
||||
ImGui.text("Position (Client): " + EntityUtils.getPosition(clientEntity));
|
||||
ImGui.text("Rotation (Client): " + EntityUtils.getRotation(clientEntity));
|
||||
ImGui.text("Velocity (Client): " + clientPhysicsBody.getLinearVel());
|
||||
ImGui.text("Force (Client): " + clientPhysicsBody.getForce());
|
||||
ImGui.text("Angular Velocity: " + clientPhysicsBody.getAngularVel());
|
||||
ImGui.text("Torque: " + clientPhysicsBody.getTorque());
|
||||
ImGui.text("Move Vector (Client): " + CreatureUtils.getFacingVector(clientEntity));
|
||||
ImGui.text("Velocity (Client): " + CreatureUtils.getVelocity(clientEntity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import electrosphere.entity.EntityUtils;
|
||||
import electrosphere.entity.state.attack.ClientAttackTree;
|
||||
import electrosphere.entity.state.equip.ClientEquipState;
|
||||
import electrosphere.entity.state.inventory.InventoryUtils;
|
||||
import electrosphere.entity.state.physicssync.ClientPhysicsSyncTree;
|
||||
import electrosphere.entity.types.attach.AttachUtils;
|
||||
import electrosphere.entity.types.creature.CreatureEquipData.EquippedItem;
|
||||
import electrosphere.entity.types.creature.CreatureTemplate;
|
||||
@ -35,12 +36,13 @@ import electrosphere.util.Utilities;
|
||||
public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
|
||||
|
||||
//Messages to ignore when complaining about messages that have nonexistant entity associated
|
||||
static List<EntityMessageType> spawnMessageTypes = Arrays.asList(new EntityMessageType[]{
|
||||
static List<EntityMessageType> idModifyingMessages = Arrays.asList(new EntityMessageType[]{
|
||||
EntityMessageType.CREATE,
|
||||
EntityMessageType.SPAWNCREATURE,
|
||||
EntityMessageType.SPAWNFOLIAGESEED,
|
||||
EntityMessageType.SPAWNITEM,
|
||||
EntityMessageType.SPAWNOBJECT,
|
||||
EntityMessageType.DESTROY,
|
||||
});
|
||||
|
||||
@Override
|
||||
@ -54,7 +56,7 @@ public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
|
||||
LoggerInterface.loggerNetworking.DEBUG_LOOP("Parse entity message of type " + message.getMessageSubtype());
|
||||
|
||||
//error check
|
||||
if(Globals.clientScene != null && Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()) == null && !spawnMessageTypes.contains(message.getMessageSubtype())){
|
||||
if(Globals.clientScene != null && Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()) == null && !idModifyingMessages.contains(message.getMessageSubtype())){
|
||||
LoggerInterface.loggerNetworking.WARNING("Client received packet for entity that is not in the client scene!");
|
||||
Globals.clientSceneWrapper.dumpTranslationLayerStatus();
|
||||
Globals.clientSceneWrapper.dumpIdData(message.getentityID());
|
||||
@ -180,6 +182,13 @@ public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
|
||||
ClientAttackTree.getClientAttackTree(Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID())).addNetworkMessage(message);
|
||||
} break;
|
||||
|
||||
case SYNCPHYSICS: {
|
||||
Entity entity = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID());
|
||||
if(entity != null && ClientPhysicsSyncTree.hasTree(entity)){
|
||||
ClientPhysicsSyncTree.getTree(entity).setMessage(message);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
@ -187,7 +196,10 @@ public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
|
||||
//
|
||||
//
|
||||
case DESTROY: {
|
||||
EntityUtils.cleanUpEntity(Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID()));
|
||||
Entity entity = Globals.clientSceneWrapper.getEntityFromServerId(message.getentityID());
|
||||
if(entity != null){
|
||||
EntityUtils.cleanUpEntity(entity);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
||||
@ -200,8 +212,8 @@ public class EntityProtocol implements ClientProtocolTemplate<EntityMessage> {
|
||||
case KILL:
|
||||
//to be implemented
|
||||
throw new UnsupportedOperationException();
|
||||
default:
|
||||
//unused
|
||||
case STARTATTACK:
|
||||
//silently ignore
|
||||
break;
|
||||
}
|
||||
Globals.profiler.endCpuSample();
|
||||
|
||||
@ -21,6 +21,7 @@ public class EntityMessage extends NetworkMessage {
|
||||
ATTACHENTITYTOENTITY,
|
||||
SPAWNFOLIAGESEED,
|
||||
UPDATEENTITYVIEWDIR,
|
||||
SYNCPHYSICS,
|
||||
}
|
||||
|
||||
EntityMessageType messageType;
|
||||
@ -35,6 +36,18 @@ public class EntityMessage extends NetworkMessage {
|
||||
double rotationY;
|
||||
double rotationZ;
|
||||
double rotationW;
|
||||
double linVelX;
|
||||
double linVelY;
|
||||
double linVelZ;
|
||||
double angVelX;
|
||||
double angVelY;
|
||||
double angVelZ;
|
||||
double linForceX;
|
||||
double linForceY;
|
||||
double linForceZ;
|
||||
double angForceX;
|
||||
double angForceY;
|
||||
double angForceZ;
|
||||
double yaw;
|
||||
double pitch;
|
||||
double velocity;
|
||||
@ -151,6 +164,102 @@ public class EntityMessage extends NetworkMessage {
|
||||
this.rotationW = rotationW;
|
||||
}
|
||||
|
||||
public double getlinVelX() {
|
||||
return linVelX;
|
||||
}
|
||||
|
||||
public void setlinVelX(double linVelX) {
|
||||
this.linVelX = linVelX;
|
||||
}
|
||||
|
||||
public double getlinVelY() {
|
||||
return linVelY;
|
||||
}
|
||||
|
||||
public void setlinVelY(double linVelY) {
|
||||
this.linVelY = linVelY;
|
||||
}
|
||||
|
||||
public double getlinVelZ() {
|
||||
return linVelZ;
|
||||
}
|
||||
|
||||
public void setlinVelZ(double linVelZ) {
|
||||
this.linVelZ = linVelZ;
|
||||
}
|
||||
|
||||
public double getangVelX() {
|
||||
return angVelX;
|
||||
}
|
||||
|
||||
public void setangVelX(double angVelX) {
|
||||
this.angVelX = angVelX;
|
||||
}
|
||||
|
||||
public double getangVelY() {
|
||||
return angVelY;
|
||||
}
|
||||
|
||||
public void setangVelY(double angVelY) {
|
||||
this.angVelY = angVelY;
|
||||
}
|
||||
|
||||
public double getangVelZ() {
|
||||
return angVelZ;
|
||||
}
|
||||
|
||||
public void setangVelZ(double angVelZ) {
|
||||
this.angVelZ = angVelZ;
|
||||
}
|
||||
|
||||
public double getlinForceX() {
|
||||
return linForceX;
|
||||
}
|
||||
|
||||
public void setlinForceX(double linForceX) {
|
||||
this.linForceX = linForceX;
|
||||
}
|
||||
|
||||
public double getlinForceY() {
|
||||
return linForceY;
|
||||
}
|
||||
|
||||
public void setlinForceY(double linForceY) {
|
||||
this.linForceY = linForceY;
|
||||
}
|
||||
|
||||
public double getlinForceZ() {
|
||||
return linForceZ;
|
||||
}
|
||||
|
||||
public void setlinForceZ(double linForceZ) {
|
||||
this.linForceZ = linForceZ;
|
||||
}
|
||||
|
||||
public double getangForceX() {
|
||||
return angForceX;
|
||||
}
|
||||
|
||||
public void setangForceX(double angForceX) {
|
||||
this.angForceX = angForceX;
|
||||
}
|
||||
|
||||
public double getangForceY() {
|
||||
return angForceY;
|
||||
}
|
||||
|
||||
public void setangForceY(double angForceY) {
|
||||
this.angForceY = angForceY;
|
||||
}
|
||||
|
||||
public double getangForceZ() {
|
||||
return angForceZ;
|
||||
}
|
||||
|
||||
public void setangForceZ(double angForceZ) {
|
||||
this.angForceZ = angForceZ;
|
||||
}
|
||||
|
||||
public double getyaw() {
|
||||
return yaw;
|
||||
}
|
||||
@ -355,6 +464,12 @@ public class EntityMessage extends NetworkMessage {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS:
|
||||
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS_SIZE){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -829,6 +944,60 @@ public class EntityMessage extends NetworkMessage {
|
||||
return rVal;
|
||||
}
|
||||
|
||||
public static EntityMessage parsesyncPhysicsMessage(CircularByteBuffer byteBuffer){
|
||||
EntityMessage rVal = new EntityMessage(EntityMessageType.SYNCPHYSICS);
|
||||
stripPacketHeader(byteBuffer);
|
||||
rVal.setentityID(ByteStreamUtils.popIntFromByteQueue(byteBuffer));
|
||||
rVal.settime(ByteStreamUtils.popLongFromByteQueue(byteBuffer));
|
||||
rVal.setpositionX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setpositionY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setpositionZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setrotationX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setrotationY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setrotationZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setrotationW(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setlinVelX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setlinVelY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setlinVelZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setangVelX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setangVelY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setangVelZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setlinForceX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setlinForceY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setlinForceZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setangForceX(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setangForceY(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
rVal.setangForceZ(ByteStreamUtils.popDoubleFromByteQueue(byteBuffer));
|
||||
return rVal;
|
||||
}
|
||||
|
||||
public static EntityMessage constructsyncPhysicsMessage(int entityID,long time,double positionX,double positionY,double positionZ,double rotationX,double rotationY,double rotationZ,double rotationW,double linVelX,double linVelY,double linVelZ,double angVelX,double angVelY,double angVelZ,double linForceX,double linForceY,double linForceZ,double angForceX,double angForceY,double angForceZ){
|
||||
EntityMessage rVal = new EntityMessage(EntityMessageType.SYNCPHYSICS);
|
||||
rVal.setentityID(entityID);
|
||||
rVal.settime(time);
|
||||
rVal.setpositionX(positionX);
|
||||
rVal.setpositionY(positionY);
|
||||
rVal.setpositionZ(positionZ);
|
||||
rVal.setrotationX(rotationX);
|
||||
rVal.setrotationY(rotationY);
|
||||
rVal.setrotationZ(rotationZ);
|
||||
rVal.setrotationW(rotationW);
|
||||
rVal.setlinVelX(linVelX);
|
||||
rVal.setlinVelY(linVelY);
|
||||
rVal.setlinVelZ(linVelZ);
|
||||
rVal.setangVelX(angVelX);
|
||||
rVal.setangVelY(angVelY);
|
||||
rVal.setangVelZ(angVelZ);
|
||||
rVal.setlinForceX(linForceX);
|
||||
rVal.setlinForceY(linForceY);
|
||||
rVal.setlinForceZ(linForceZ);
|
||||
rVal.setangForceX(angForceX);
|
||||
rVal.setangForceY(angForceY);
|
||||
rVal.setangForceZ(angForceZ);
|
||||
rVal.serialize();
|
||||
return rVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
void serialize(){
|
||||
byte[] intValues = new byte[8];
|
||||
@ -1205,6 +1374,97 @@ public class EntityMessage extends NetworkMessage {
|
||||
rawBytes[26+i] = intValues[i];
|
||||
}
|
||||
break;
|
||||
case SYNCPHYSICS:
|
||||
rawBytes = new byte[2+4+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8+8];
|
||||
//message header
|
||||
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
|
||||
//entity messaage header
|
||||
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS;
|
||||
intValues = ByteStreamUtils.serializeIntToBytes(entityID);
|
||||
for(int i = 0; i < 4; i++){
|
||||
rawBytes[2+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeLongToBytes(time);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[6+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(positionX);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[14+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(positionY);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[22+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(positionZ);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[30+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(rotationX);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[38+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(rotationY);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[46+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(rotationZ);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[54+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(rotationW);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[62+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(linVelX);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[70+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(linVelY);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[78+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(linVelZ);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[86+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(angVelX);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[94+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(angVelY);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[102+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(angVelZ);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[110+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(linForceX);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[118+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(linForceY);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[126+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(linForceZ);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[134+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(angForceX);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[142+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(angForceY);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[150+i] = intValues[i];
|
||||
}
|
||||
intValues = ByteStreamUtils.serializeDoubleToBytes(angForceZ);
|
||||
for(int i = 0; i < 8; i++){
|
||||
rawBytes[158+i] = intValues[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
serialized = true;
|
||||
}
|
||||
|
||||
@ -107,6 +107,11 @@ COMBAT_MESSAGE,
|
||||
rVal = EntityMessage.parseupdateEntityViewDirMessage(byteBuffer);
|
||||
}
|
||||
break;
|
||||
case TypeBytes.ENTITY_MESSAGE_TYPE_SYNCPHYSICS:
|
||||
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
|
||||
rVal = EntityMessage.parsesyncPhysicsMessage(byteBuffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TypeBytes.MESSAGE_TYPE_LORE:
|
||||
|
||||
@ -31,6 +31,7 @@ Message categories
|
||||
public static final byte ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY = 10;
|
||||
public static final byte ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED = 11;
|
||||
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR = 12;
|
||||
public static final byte ENTITY_MESSAGE_TYPE_SYNCPHYSICS = 13;
|
||||
/*
|
||||
Entity packet sizes
|
||||
*/
|
||||
@ -41,6 +42,7 @@ Message categories
|
||||
public static final byte ENTITY_MESSAGE_TYPE_DESTROY_SIZE = 6;
|
||||
public static final byte ENTITY_MESSAGE_TYPE_SETPROPERTY_SIZE = 22;
|
||||
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR_SIZE = 34;
|
||||
public static final short ENTITY_MESSAGE_TYPE_SYNCPHYSICS_SIZE = 166;
|
||||
/*
|
||||
Lore subcategories
|
||||
*/
|
||||
|
||||
@ -65,6 +65,7 @@ public class EntityProtocol implements ServerProtocolTemplate<EntityMessage> {
|
||||
case SPAWNFOLIAGESEED:
|
||||
case SPAWNITEM:
|
||||
case SPAWNOBJECT:
|
||||
case SYNCPHYSICS:
|
||||
//silently ignore
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package electrosphere.server.ai.creature;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.joml.Quaterniond;
|
||||
import org.joml.Vector3d;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
@ -85,7 +86,8 @@ public class Blocker implements AITree {
|
||||
}
|
||||
if(target != null){
|
||||
Vector3d targetPos = EntityUtils.getPosition(target);
|
||||
EntityUtils.getRotation(parent).set(MathUtils.calculateRotationFromPointToPoint(EntityUtils.getPosition(parent), targetPos));
|
||||
Quaterniond rotation = MathUtils.calculateRotationFromPointToPoint(EntityUtils.getPosition(parent), targetPos);
|
||||
EntityUtils.getRotation(parent).set(rotation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -24,13 +24,20 @@ public class PlayerCharacterCreation {
|
||||
*/
|
||||
public static void spawnPlayerCharacter(ServerConnectionHandler connectionHandler){
|
||||
Player playerObject = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
|
||||
Realm realm = Globals.realmManager.getRealms().iterator().next();
|
||||
|
||||
//
|
||||
//get template
|
||||
CreatureTemplate template = connectionHandler.getCurrentCreatureTemplate();
|
||||
String raceName = template.getCreatureType();
|
||||
|
||||
//
|
||||
//spawn entity in world
|
||||
Realm realm = Globals.realmManager.getRealms().iterator().next();
|
||||
Vector3d spawnPoint = realm.getSpawnPoint();
|
||||
Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(spawnPoint.x,spawnPoint.y,spawnPoint.z),raceName,template);
|
||||
|
||||
//
|
||||
//attach entity to player object
|
||||
LoggerInterface.loggerEngine.INFO("Spawned entity for player. Entity id: " + newPlayerEntity.getId() + " Player id: " + playerObject.getId());
|
||||
int playerCharacterId = newPlayerEntity.getId();
|
||||
connectionHandler.setPlayerEntityId(playerCharacterId);
|
||||
@ -45,6 +52,13 @@ public class PlayerCharacterCreation {
|
||||
realm.getServerWorldData().convertRealToChunkSpace(spawnPoint.z)
|
||||
));
|
||||
realm.getDataCellManager().addPlayerToRealm(playerObject);
|
||||
|
||||
//
|
||||
//error checking
|
||||
Realm searchedRealm = Globals.realmManager.getEntityRealm(newPlayerEntity);
|
||||
if(searchedRealm == null){
|
||||
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Player entity created but not attached to a realm!"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -6,6 +6,7 @@ import org.joml.Vector3d;
|
||||
|
||||
import electrosphere.engine.Globals;
|
||||
import electrosphere.entity.Entity;
|
||||
import electrosphere.logger.LoggerInterface;
|
||||
import electrosphere.server.datacell.Realm;
|
||||
import electrosphere.server.datacell.ServerDataCell;
|
||||
|
||||
@ -20,7 +21,15 @@ public class DataCellSearchUtils {
|
||||
* @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);
|
||||
if(entity == null){
|
||||
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Trying to get entity data cell of null!"));
|
||||
}
|
||||
Realm realm = Globals.realmManager.getEntityRealm(entity);
|
||||
if(realm == null){
|
||||
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Trying to get entity data cell of an entity that is not assigned to a realm!"));
|
||||
return null;
|
||||
}
|
||||
return realm.getEntityDataCellMapper().getEntityDataCell(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -35,8 +35,9 @@ public class ServerBehaviorTreeUtils {
|
||||
Set<BehaviorTree> trees = entityBTreeMap.remove(entity);
|
||||
ServerDataCell currentCell = DataCellSearchUtils.getEntityDataCell(entity);
|
||||
for(BehaviorTree tree : trees){
|
||||
currentCell.getScene().registerBehaviorTree(tree);
|
||||
currentCell.getScene().deregisterBehaviorTree(tree);
|
||||
}
|
||||
currentCell.getScene().deregisterEntity(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -85,6 +85,14 @@ public class MathUtils {
|
||||
return new Vector3f(0,0,1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the up rotation
|
||||
* @return The up rotation
|
||||
*/
|
||||
public static Quaterniond getUpRotation(){
|
||||
return MathUtils.calculateRotationFromPointToPoint(MathUtils.getOriginVector(), MathUtils.getUpVector());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the quaternion that rotates the origin vector to point from origin to destination
|
||||
|
||||
Loading…
Reference in New Issue
Block a user