Renderer/src/main/java/electrosphere/collision/PhysicsEntityUtils.java
2025-06-04 11:53:42 -04:00

1058 lines
54 KiB
Java

package electrosphere.collision;
import java.util.LinkedList;
import java.util.List;
import org.joml.Matrix4d;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DGeom;
import electrosphere.collision.collidable.Collidable;
import electrosphere.data.entity.collidable.CollidableTemplate;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.state.collidable.ClientCollidableTree;
import electrosphere.entity.state.collidable.MultiShapeTriGeomData;
import electrosphere.entity.state.collidable.ServerCollidableTree;
import electrosphere.entity.state.collidable.TriGeomData;
import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.physicssync.ClientPhysicsSyncTree;
import electrosphere.entity.state.physicssync.ServerPhysicsSyncTree;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerWorldData;
import electrosphere.server.datacell.utils.ServerEntityTagUtils;
/**
* Utilities for performing physics-related operations on entities (particularly attaching physics to them in the first place)
*/
public class PhysicsEntityUtils {
/**
* The linear velocity threshold to disable under
*/
static final double LINEAR_THRESHOLD = 3;
/**
* The angular velocity threshold to disable under
*/
static final double ANGULAR_THRESHOLD = 3;
/**
* The number of steps below threshold to disable after
*/
static final int STEP_THRESHOLD = 4;
/**
* How close to the edge to position an entity if it overruns the edge
*/
static final double WORLD_MARGIN = 0.001;
/**
* Distance after which client does not generate collidables by default
*/
public static final double CLIENT_LOD_DIST = 50;
/**
* [CLIENT ONLY] Attaches a collidable template to a given entity
* @param rVal The entity
* @param physicsTemplate The collidable template
*/
public static void clientAttachCollidableTemplate(Entity rVal, CollidableTemplate physicsTemplate){
Collidable collidable;
double mass = 1.0f;
CollisionEngine engine = Globals.clientState.clientSceneWrapper.getCollisionEngine();
if(physicsTemplate.getMass() != null){
mass = physicsTemplate.getMass();
}
long categoryBit = Collidable.TYPE_CREATURE_BIT;
if(physicsTemplate.getKinematic()){
categoryBit = Collidable.TYPE_STATIC_BIT;
}
CollisionEngine.lockOde();
if(physicsTemplate.getKinematic()){
DGeom geom = null;
switch(physicsTemplate.getType()){
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
//
//create dbody
geom = CollisionBodyCreation.createCylinderShape(
engine,
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
//
//create collidable and link to structures
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
PhysicsEntityUtils.setDGeom(rVal, geom);
//
//store values
Matrix4d offsetTransform = new Matrix4d().translationRotate(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW() //rotate
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
engine.registerCollisionObject(geom, collidable);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
//
//create dbody
geom = CollisionBodyCreation.createCubeShape(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
categoryBit
);
//
//create collidable and link to structures
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
PhysicsEntityUtils.setDGeom(rVal,geom);
//
//store values
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
engine.registerCollisionObject(geom, collidable);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
//
//create dbody
geom = CollisionBodyCreation.createCapsuleShape(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
//
//create collidable and link to structures
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
PhysicsEntityUtils.setDGeom(rVal,geom);
//
//store values
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
engine.registerCollisionObject(geom, collidable);
} break;
}
} else {
DBody rigidBody = null;
switch(physicsTemplate.getType()){
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCylinderBody(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setCylinderMass(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
rigidBody,
mass,
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
);
}
CollisionBodyCreation.setAutoDisable(Globals.clientState.clientSceneWrapper.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from center of entity position
CollisionBodyCreation.setOffsetPosition(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and link to structures
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store values
Matrix4d offsetTransform = new Matrix4d().translationRotate(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW() //rotate
);
if(physicsTemplate.isAngularlyStatic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable, EntityUtils.getPosition(rVal));
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCubeBody(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setBoxMass(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
rigidBody,
mass,
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
);
}
CollisionBodyCreation.setAutoDisable(Globals.clientState.clientSceneWrapper.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from center of entity position
CollisionBodyCreation.setOffsetPosition(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and link to structures
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store values
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable, EntityUtils.getPosition(rVal));
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCapsuleBody(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setCapsuleMass(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
rigidBody,
mass,
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
);
}
CollisionBodyCreation.setAutoDisable(Globals.clientState.clientSceneWrapper.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from center of entity position
CollisionBodyCreation.setOffsetPosition(
Globals.clientState.clientSceneWrapper.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and link to structures
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ClientCollidableTree tree = new ClientCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store values
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
Globals.clientState.clientSceneWrapper.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.CLIENT_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable, EntityUtils.getPosition(rVal));
Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE);
} break;
}
//if we successfully attached the body, add a sync tree
if(rigidBody != null){
ClientPhysicsSyncTree.attachTree(rVal);
if(ClientGravityTree.hasClientGravityTree(rVal)){
ClientGravityTree.getClientGravityTree(rVal).updatePhysicsPair(PhysicsEntityUtils.getCollidable(rVal),PhysicsEntityUtils.getDBody(rVal));
}
}
}
CollisionEngine.unlockOde();
}
/**
* [SERVER ONLY] Attaches a collidable template to a given entity
* @param realm The realm the entity is inside of
* @param rVal The entity
* @param physicsTemplate The collidable template
* @param position the position of the body
*/
public static void serverAttachCollidableTemplate(Realm realm, Entity rVal, CollidableTemplate physicsTemplate, Vector3d position){
Collidable collidable;
double mass = 1.0f;
if(physicsTemplate.getMass() != null){
mass = physicsTemplate.getMass();
}
long categoryBit = Collidable.TYPE_CREATURE_BIT;
if(physicsTemplate.getKinematic()){
categoryBit = Collidable.TYPE_STATIC_BIT;
}
CollisionEngine.lockOde();
if(physicsTemplate.getKinematic()){
DGeom geom = PhysicsEntityUtils.serverAttachGeom(realm,rVal,physicsTemplate);
PhysicsUtils.makeGeomStatic(realm.getCollisionEngine(), geom);
} else {
DBody rigidBody = null;
switch(physicsTemplate.getType()){
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCylinderBody(
realm.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setCylinderMass(
realm.getCollisionEngine(),
rigidBody,
mass,
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
);
}
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from entity center
CollisionBodyCreation.setOffsetPosition(
realm.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
realm.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
realm.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable, position);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCubeBody(
realm.getCollisionEngine(),
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setBoxMass(
realm.getCollisionEngine(),
rigidBody,
mass,
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
);
}
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from entity center
CollisionBodyCreation.setOffsetPosition(
realm.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
realm.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
realm.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable, position);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
//
//create dbody
rigidBody = CollisionBodyCreation.createCapsuleBody(
realm.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
if(physicsTemplate.getMass() != null){
CollisionBodyCreation.setCapsuleMass(
realm.getCollisionEngine(),
rigidBody,
mass,
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ()),
new Quaterniond(physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW())
);
}
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), rigidBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
//
//set offset from entity center
CollisionBodyCreation.setOffsetPosition(
realm.getCollisionEngine(),
rigidBody,
new Vector3d(physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ())
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
if(physicsTemplate.getLinearFriction() != null){
collidable.getSurfaceParams().setLinearFriction(physicsTemplate.getLinearFriction());
}
if(physicsTemplate.getRollingFriction() != null){
collidable.getSurfaceParams().setRollingFriction(physicsTemplate.getRollingFriction());
}
ServerCollidableTree tree = new ServerCollidableTree(rVal,collidable,rigidBody);
PhysicsEntityUtils.setDBody(rVal,rigidBody);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
if(physicsTemplate.isAngularlyStatic()){
realm.getCollisionEngine().setAngularlyStatic(rigidBody, true);
}
if(physicsTemplate.getKinematic()){
realm.getCollisionEngine().setKinematic(rigidBody);
rigidBody.disable();
}
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.SERVER_COLLIDABLE_TREE, tree);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable, position);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
} break;
}
//if we successfully attached the body, add a sync tree
if(rigidBody != null){
ServerPhysicsSyncTree.attachTree(rVal);
if(ServerGravityTree.hasServerGravityTree(rVal)){
ServerGravityTree.getServerGravityTree(rVal).updatePhysicsPair(PhysicsEntityUtils.getCollidable(rVal),PhysicsEntityUtils.getDBody(rVal));
}
}
}
CollisionEngine.unlockOde();
}
/**
* [SERVER ONLY] Attaches a collidable template to a given entity
* @param realm The realm the entity is inside of
* @param rVal The entity
* @param physicsTemplate The collidable template
* @return The geometry object
*/
public static DGeom serverAttachGeom(Realm realm, Entity rVal, CollidableTemplate physicsTemplate){
if(physicsTemplate == null){
throw new Error("Physics template is null!");
}
Collidable collidable;
double mass = 1.0f;
long categoryBit = Collidable.TYPE_STATIC_BIT;
CollisionEngine.lockOde();
DGeom geom = null;
switch(physicsTemplate.getType()){
case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: {
//
//create dbody
geom = CollisionBodyCreation.createCylinderShape(
realm.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
PhysicsEntityUtils.setDGeom(rVal, geom);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
realm.getCollisionEngine().registerCollisionObject(geom, collidable);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CUBE: {
//
//create dbody
geom = CollisionBodyCreation.createCubeShape(
realm.getCollisionEngine(),
new Vector3d(physicsTemplate.getDimension1(),physicsTemplate.getDimension2(),physicsTemplate.getDimension3()),
categoryBit
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
PhysicsEntityUtils.setDGeom(rVal, geom);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
realm.getCollisionEngine().registerCollisionObject(geom, collidable);
} break;
case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: {
//
//create dbody
geom = CollisionBodyCreation.createCapsuleShape(
realm.getCollisionEngine(),
physicsTemplate.getDimension1(),
physicsTemplate.getDimension2(),
categoryBit
);
//
//create collidable and attach tracking
collidable = new Collidable(rVal, Collidable.TYPE_CREATURE, true);
PhysicsEntityUtils.setDGeom(rVal, geom);
//
//store data
Matrix4d offsetTransform = new Matrix4d().translationRotateScale(
physicsTemplate.getOffsetX(), physicsTemplate.getOffsetY(), physicsTemplate.getOffsetZ(), //translate
physicsTemplate.getRotX(), physicsTemplate.getRotY(), physicsTemplate.getRotZ(), physicsTemplate.getRotW(), //rotate
1, 1, 1 //scale
);
rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform);
rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate);
rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
rVal.putData(EntityDataStrings.PHYSICS_MASS, mass);
ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE);
realm.getCollisionEngine().registerCollisionObject(geom, collidable);
} break;
}
if(geom != null){
realm.getCollisionEngine().addToStaticSpace(geom);
}
CollisionEngine.unlockOde();
return geom;
}
/**
* [CLIENT ONLY] Given an entity and a terrain chunk description, create physics for the chunk and attach it to the entity
* @param terrain The entity
* @param data The terrain description
* @return The rigid body created (note, attachment has already been performed)
*/
public static void clientAttachTriGeomRigidBody(Entity terrain, TriGeomData data){
CollisionEngine.lockOde();
DBody terrainBody = CollisionBodyCreation.generateBodyFromTerrainData(Globals.clientState.clientSceneWrapper.getCollisionEngine(), data, Collidable.TYPE_STATIC_BIT);
CollisionBodyCreation.setAutoDisable(Globals.clientState.clientSceneWrapper.getCollisionEngine(), terrainBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
Collidable collidable = new Collidable(terrain,Collidable.TYPE_STATIC, false);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(terrainBody, collidable, EntityUtils.getPosition(terrain));
PhysicsEntityUtils.setDBody(terrain,terrainBody);
CollisionEngine.unlockOde();
terrain.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
}
/**
* [CLIENT ONLY] Given an entity and a terrain chunk description, create physics for the chunk and attach it to the entity
* @param terrain The entity
* @param data The terrain description
* @return The rigid body created (note, attachment has already been performed)
*/
public static void clientAttachTriGeomCollider(Entity terrain, TriGeomData data){
CollisionEngine.lockOde();
DGeom terrainGeom = CollisionBodyCreation.generateGeomFromTerrainData(Globals.clientState.clientSceneWrapper.getCollisionEngine(), data, Collidable.TYPE_STATIC_BIT);
Collidable collidable = new Collidable(terrain,Collidable.TYPE_STATIC, true);
PhysicsEntityUtils.setCollidable(terrain, collidable);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(terrainGeom, collidable);
CollisionEngine.unlockOde();
PhysicsEntityUtils.setDGeom(terrain,terrainGeom);
}
/**
* [CLIENT ONLY] Given an entity and a multi-shape trimesh description, create physics for the shapes and attach it to the entity
* @param terrain The entity
* @param data The trimesh description
* @return The rigid body created (note, attachment has already been performed)
*/
public static void clientAttachMultiShapeTriGeomRigidBody(Entity terrain, MultiShapeTriGeomData data){
DBody terrainBody = CollisionBodyCreation.generateBodyFromMultiShapeMeshData(Globals.clientState.clientSceneWrapper.getCollisionEngine(), data, Collidable.TYPE_STATIC_BIT);
CollisionBodyCreation.setAutoDisable(Globals.clientState.clientSceneWrapper.getCollisionEngine(), terrainBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
Collidable collidable = new Collidable(terrain,Collidable.TYPE_STATIC, false);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(terrainBody, collidable, EntityUtils.getPosition(terrain));
PhysicsEntityUtils.setDBody(terrain,terrainBody);
terrain.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
}
/**
* [CLIENT ONLY] Given an entity and a multi-shape trimesh description, create physics for the shapes and attach it to the entity
* @param terrain The entity
* @param data The trimesh description
* @return The collider created (note, attachment has already been performed)
*/
public static void clientAttachMultiShapeTriGeomCollider(Entity terrain, MultiShapeTriGeomData data){
DGeom terrainBody = CollisionBodyCreation.generateColliderFromMultiShapeMeshData(Globals.clientState.clientSceneWrapper.getCollisionEngine(), data, Collidable.TYPE_STATIC_BIT);
Collidable collidable = new Collidable(terrain,Collidable.TYPE_STATIC, false);
PhysicsEntityUtils.setCollidable(terrain, collidable);
Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(terrainBody, collidable);
PhysicsEntityUtils.setDGeom(terrain,terrainBody);
}
/**
* [SERVER ONLY] Given an entity and a terrain chunk description, create physics for the chunk and attach it to the entity
* @param terrain The entity
* @param data The terrain description
* @return The rigid body created (note, attachment has already been performed)
*/
public static DBody serverAttachTriGeomRigidBody(Entity terrain, TriGeomData data){
Realm realm = Globals.serverState.realmManager.getEntityRealm(terrain);
DBody terrainBody = CollisionBodyCreation.generateBodyFromTerrainData(realm.getCollisionEngine(),data,Collidable.TYPE_STATIC_BIT);
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), terrainBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
realm.getCollisionEngine().registerCollisionObject(terrainBody, new Collidable(terrain,Collidable.TYPE_STATIC, false), EntityUtils.getPosition(terrain));
PhysicsEntityUtils.setDBody(terrain,terrainBody);
return terrainBody;
}
/**
* [SERVER ONLY] Given an entity and a terrain chunk description, create physics for the chunk and attach it to the entity
* @param terrain The entity
* @param data The terrain description
* @return The rigid body created (note, attachment has already been performed)
*/
public static DGeom serverAttachTriGeomCollider(Entity terrain, TriGeomData data){
Realm realm = Globals.serverState.realmManager.getEntityRealm(terrain);
DGeom terrainCollider = CollisionBodyCreation.generateGeomFromTerrainData(realm.getCollisionEngine(),data,Collidable.TYPE_STATIC_BIT);
Collidable collidable = new Collidable(terrain,Collidable.TYPE_STATIC, true);
PhysicsEntityUtils.setCollidable(terrain, collidable);
realm.getCollisionEngine().registerCollisionObject(terrainCollider, collidable);
PhysicsEntityUtils.setDGeom(terrain,terrainCollider);
PhysicsUtils.makeGeomStatic(realm.getCollisionEngine(), terrainCollider);
return terrainCollider;
}
/**
* [SERVER ONLY] Given an entity and a multi-shape trimesh description, create physics for the shapes and attach it to the entity
* @param terrain The entity
* @param data The trimesh description
* @return The rigid body created (note, attachment has already been performed)
*/
public static DBody serverAttachMultiShapeTriGeomRigidBody(Entity terrain, MultiShapeTriGeomData data){
Realm realm = Globals.serverState.realmManager.getEntityRealm(terrain);
DBody terrainBody = CollisionBodyCreation.generateBodyFromMultiShapeMeshData(realm.getCollisionEngine(),data,Collidable.TYPE_STATIC_BIT);
CollisionBodyCreation.setAutoDisable(realm.getCollisionEngine(), terrainBody, true, LINEAR_THRESHOLD, ANGULAR_THRESHOLD, STEP_THRESHOLD);
realm.getCollisionEngine().registerCollisionObject(terrainBody, new Collidable(terrain,Collidable.TYPE_STATIC, false), EntityUtils.getPosition(terrain));
PhysicsEntityUtils.setDBody(terrain,terrainBody);
return terrainBody;
}
/**
* [SERVER ONLY] Given an entity and a multi-shape trimesh description, create physics for the shapes and attach it to the entity
* @param terrain The entity
* @param data The trimesh description
* @return The rigid body created (note, attachment has already been performed)
*/
public static DGeom serverAttachMultiShapeTriGeomCollider(Entity terrain, MultiShapeTriGeomData data){
Realm realm = Globals.serverState.realmManager.getEntityRealm(terrain);
DGeom terrainBody = CollisionBodyCreation.generateColliderFromMultiShapeMeshData(realm.getCollisionEngine(),data,Collidable.TYPE_STATIC_BIT);
Collidable collidable = new Collidable(terrain,Collidable.TYPE_STATIC, false);
PhysicsEntityUtils.setCollidable(terrain, collidable);
realm.getCollisionEngine().registerCollisionObject(terrainBody, collidable);
PhysicsEntityUtils.setDGeom(terrain,terrainBody);
PhysicsUtils.makeGeomStatic(realm.getCollisionEngine(), terrainBody);
return terrainBody;
}
/**
* Repositions all active physics-scoped entities on a given realm
* @param collisionEngine The realm's collision engine
*/
public static void serverRepositionEntities(Realm realm, CollisionEngine collisionEngine){
List<Entity> toReposition = new LinkedList<Entity>();
List<Collidable> collidableList = collisionEngine.getCollidables();
if(collidableList == null){
collisionEngine.getCollidables();
throw new Error("Collision engine collidables are null!");
}
for(int i = 0; i < collidableList.size(); i++){
Collidable collidable = collidableList.get(i);
Entity entity = collidable.getParent();
DBody body = PhysicsEntityUtils.getDBody(entity);
if(body != null && body.isEnabled() && !body.isKinematic()){
toReposition.add(entity);
}
}
ServerWorldData worldDat = realm.getServerWorldData();
for(Entity parent : toReposition){
Vector3d parentPos = EntityUtils.getPosition(parent);
if(ServerWorldData.convertRealToChunkSpace(parentPos.x) >= worldDat.getWorldSizeDiscrete()){
parentPos.x = ServerWorldData.convertWorldToReal(worldDat.getWorldSizeDiscrete()) - WORLD_MARGIN;
}
if(ServerWorldData.convertRealToChunkSpace(parentPos.y) >= worldDat.getWorldSizeDiscrete()){
parentPos.y = ServerWorldData.convertWorldToReal(worldDat.getWorldSizeDiscrete()) - WORLD_MARGIN;
}
if(ServerWorldData.convertRealToChunkSpace(parentPos.z) >= worldDat.getWorldSizeDiscrete()){
parentPos.z = ServerWorldData.convertWorldToReal(worldDat.getWorldSizeDiscrete()) - WORLD_MARGIN;
}
ServerEntityUtils.repositionEntity(parent,parentPos);
}
}
/**
* Destroys the physics attached to an entity without outright destroying the entity
* @param entity The entity
*/
public static void serverDestroyPhysics(Entity entity){
Realm realm = Globals.serverState.realmManager.getEntityRealm(entity);
realm.getCollisionEngine().destroyPhysics(entity);
Vector3d entityPos = EntityUtils.getPosition(entity);
ServerEntityUtils.repositionEntity(entity, entityPos);
}
/**
* Gets the transform from parent entity position to rigid body
* @param entity The entity
* @return The transform
*/
public static Matrix4d getEntityCollidableTransform(Entity entity){
return (Matrix4d) entity.getData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM);
}
/**
* Checks if the entity contains a dbody
* @param entity the entity
* @return true if contains, false otherwise
*/
public static boolean containsDBody(Entity entity){
return entity.containsKey(EntityDataStrings.PHYSICS_COLLISION_BODY);
}
/**
* Sets the dbody on the entity
* @param entity The entity
* @param body The body
*/
public static void setDBody(Entity entity, DBody body){
if(body == null){
throw new Error("Trying to set null DBody!");
}
entity.putData(EntityDataStrings.PHYSICS_COLLISION_BODY, body);
}
/**
* Gets the DBody attached to an entity
* @param entity the entity
* @return The dbody if it exists, null otherwise
*/
public static DBody getDBody(Entity entity){
return (DBody)entity.getData(EntityDataStrings.PHYSICS_COLLISION_BODY);
}
/**
* Checks if the entity contains a dgeom
* @param entity the entity
* @return true if contains, false otherwise
*/
public static boolean containsDGeom(Entity entity){
return entity.containsKey(EntityDataStrings.PHYSICS_GEOM);
}
/**
* Sets the static geom on the entity
* @param entity The entity
* @param geom The static geom
*/
public static void setDGeom(Entity entity, DGeom geom){
if(geom == null){
throw new Error("Trying to set null geom!");
}
entity.putData(EntityDataStrings.PHYSICS_GEOM, geom);
}
/**
* Gets the geom attached to the entity
* @param entity The entity
* @return The geom if it exists, null otherwise
*/
public static DGeom getDGeom(Entity entity){
return (DGeom)entity.getData(EntityDataStrings.PHYSICS_GEOM);
}
/**
* Clears the geom and body on an entity
* @param entity The entity
*/
public static void clearGeomAndBody(Entity entity){
if(PhysicsEntityUtils.getCollidable(entity) != null){
throw new Error("Trying to clear geom and body on an entity that still has a collidable!");
}
entity.removeData(EntityDataStrings.PHYSICS_COLLISION_BODY);
entity.removeData(EntityDataStrings.PHYSICS_GEOM);
}
/**
* Sets the position of a DGeom
* @param collisionEngine the collision engine
* @param geom the geometry
*/
public static void setGeometryOffsetPosition(CollisionEngine collisionEngine, DGeom geom, Vector3d position, Quaterniond rotation){
collisionEngine.setGeomOffsetTransform(geom, position, rotation);
}
/**
* Gets the collidable attached to the entity
* @param entity The entity
* @return The collidable if it exists, null otherwise
*/
public static Collidable getCollidable(Entity entity){
return (Collidable)entity.getData(EntityDataStrings.PHYSICS_COLLIDABLE);
}
/**
* Gets the collidable attached to the entity
* @param entity The entity
* @param collidable The collidable
*/
public static void setCollidable(Entity entity, Collidable collidable){
entity.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable);
}
/**
* Enables a body
* @param collisionEngine The collision engine
* @param entity The entity which contains the body to enable
*/
public static void enableBody(CollisionEngine collisionEngine, Entity entity){
DBody body = PhysicsEntityUtils.getDBody(entity);
if(body != null){
PhysicsUtils.enableBody(collisionEngine, body);
}
}
/**
* Disables a body
* @param collisionEngine The collision engine
* @param entity The entity which contains the body to disable
*/
public static void disableBody(CollisionEngine collisionEngine, Entity entity){
DBody body = PhysicsEntityUtils.getDBody(entity);
if(body != null){
PhysicsUtils.disableBody(collisionEngine, body);
}
}
/**
* Gets the physics template for the entity
* @param entity The entity
* @return The template
*/
public static CollidableTemplate getPhysicsTemplate(Entity entity){
return (CollidableTemplate)entity.getData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE);
}
}