From cbd5c98e0a4b92d9b6a7cdf20cef0df760b34afb Mon Sep 17 00:00:00 2001 From: austin Date: Wed, 21 May 2025 18:52:41 -0400 Subject: [PATCH] server-side geom colliders --- docs/src/progress/renderertodo.md | 1 + .../collision/CollisionEngine.java | 188 +++++-- .../collision/PhysicsEntityUtils.java | 473 +++++++++++------- .../types/collision/CollisionObjUtils.java | 19 +- .../ServerHitboxResolutionCallback.java | 22 +- .../server/simulation/MicroSimulation.java | 4 +- 6 files changed, 470 insertions(+), 237 deletions(-) diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 60c809e0..12c49bba 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1928,6 +1928,7 @@ Fix town placement structure-road intersection test (05/21/2025) Kinematic collision templates now use geoms instead of setting kinematic (on client) +Geom-only collidables on server diff --git a/src/main/java/electrosphere/collision/CollisionEngine.java b/src/main/java/electrosphere/collision/CollisionEngine.java index 264ba5a4..55c59ab7 100644 --- a/src/main/java/electrosphere/collision/CollisionEngine.java +++ b/src/main/java/electrosphere/collision/CollisionEngine.java @@ -25,6 +25,7 @@ import org.ode4j.ode.DGeom.DNearCallback; import org.ode4j.ode.DJoint; import org.ode4j.ode.DJointGroup; import org.ode4j.ode.DMass; +import org.ode4j.ode.DPlane; import org.ode4j.ode.DRay; import org.ode4j.ode.DSpace; import org.ode4j.ode.DSphere; @@ -94,16 +95,31 @@ public class CollisionEngine { */ public static final double DEFAULT_INTERACT_DISTANCE = 5.0; - //world data that the collision engine leverages for position correction and the like - CollisionWorldData collisionWorldData; + /** + * world data that the collision engine leverages for position correction and the like + */ + private CollisionWorldData collisionWorldData; - //Ode-specific stuff + /** + * The world object + */ private DWorld world; + + /** + * The main space in the world + */ private DSpace space; + + /** + * Lock for thread-safeing all ODE calls + */ private static ReentrantLock spaceLock = new ReentrantLock(); + + /** + * The contact group for caching collisions between collision and physics calls + */ private DJointGroup contactgroup; - // maximum number of contact points per body /** *

Maximum number of contact points per body

*

Note:

@@ -114,38 +130,57 @@ public class CollisionEngine { */ private static final int MAX_CONTACTS = 64; - //The list of dbodies ode should be tracking - List bodies = new ArrayList(); + /** + * The list of dbodies ode should be tracking + */ + private List bodies = new ArrayList(); - //This is used to relate DBody's back to their collidables so that when the library detects a collision, the callback can know which collidables are involved. - Map bodyPointerMap = new HashMap(); + /** + * This is used to relate DBody's back to their collidables so that when the library detects a collision, the callback can know which collidables are involved. + */ + private Map bodyPointerMap = new HashMap(); - //The list of all collidables the engine is currently tracking - List collidableList = new ArrayList(); + /** + * This is used to relate DGeom's back to their collidables so that when the library detects a collision, the callback can know which collidables are involved. + */ + private Map geomPointerMap = new HashMap(); + + /** + * The list of all collidables the engine is currently tracking + */ + private List collidableList = new ArrayList(); /** * Dynamic spatial offset applied to all operations on the space. * This is used for world origin rebasing. * This makes physics behave more consistently by moving far out objects to center around 0,0,0. */ - Vector3d floatingOrigin = new Vector3d(0,0,0); + private Vector3d floatingOrigin = new Vector3d(0,0,0); - //callbacks for collision check - RayCastCallback rayCastCallback = new RayCastCallback(); + /** + * callbacks for collision check + */ + private RayCastCallback rayCastCallback = new RayCastCallback(); - //the collision resolution callback - CollisionResolutionCallback collisionResolutionCallback; - - //buffer for collisions - DContactBuffer contacts = null; + /** + * the collision resolution callback + */ + private CollisionResolutionCallback collisionResolutionCallback; /** * The body that contains all static shapes */ - DBody staticBody; + private DBody staticBody; - // Callback for any near collisions in the broadphase of the collision check + /** + * Callback for any near collisions in the broadphase of the collision check + */ private DNearCallback nearCallback; + + /** + * The base plane of the physics engine + */ + private DPlane basePlane = null; /** * Constructor @@ -160,7 +195,7 @@ public class CollisionEngine { // world.setCFM(1e-10); //base plane - OdeHelper.createPlane(space, 0, 1, 0, 0); + basePlane = OdeHelper.createPlane(space, 0, 1, 0, 0); //static body staticBody = this.createDBody(); @@ -271,6 +306,9 @@ public class CollisionEngine { public void simulatePhysics(float time){ Globals.profiler.beginCpuSample("physics"); spaceLock.lock(); + // remove all contact joints + contactgroup.empty(); + //main simulation for(int i = 0; i < PHYSICS_SIMULATION_RESOLUTION; i++){ Globals.profiler.beginCpuSample("collide"); OdeHelper.spaceCollide(space, 0, nearCallback); @@ -295,6 +333,7 @@ public class CollisionEngine { public void collide(){ Globals.profiler.beginCpuSample("physics"); spaceLock.lock(); + contactgroup.empty(); Globals.profiler.beginCpuSample("collide"); OdeHelper.spaceCollide(space, 0, nearCallback); Globals.profiler.endCpuSample(); @@ -336,19 +375,52 @@ public class CollisionEngine { } //if collision is between static and disabled, skip - if(o1.getCategoryBits() == Collidable.TYPE_STATIC_BIT && !b2.isEnabled()){ + if(o1.getCategoryBits() == Collidable.TYPE_STATIC_BIT && b2 != null && !b2.isEnabled()){ return; } - if(o2.getCategoryBits() == Collidable.TYPE_STATIC_BIT && !b1.isEnabled()){ + if(o2.getCategoryBits() == Collidable.TYPE_STATIC_BIT && b1 != null && !b1.isEnabled()){ return; } - Collidable c1 = bodyPointerMap.get(b1); - Collidable c2 = bodyPointerMap.get(b2); - if(c1 == null || c2 == null){ + //check if we're colliding against the base plane + if(o1 == this.basePlane || o2 == this.basePlane){ return; } + //get the collidables for each geom + Collidable c1 = null; + if(b1 != null){ + c1 = bodyPointerMap.get(b1); + } else if(o1.getBody() == null) { + c1 = geomPointerMap.get(o1); + } + Collidable c2 = null; + if(b2 != null){ + c2 = bodyPointerMap.get(b2); + } else if(o2.getBody() == null) { + c2 = geomPointerMap.get(o2); + } + + //make sure we have collidables for both + if(c1 == null || c2 == null){ + String message = "Collidable is undefined!\n" + + o1 + " \n" + + o2 + " \n" + + b1 + " \n" + + b2 + " \n" + + c1 + " \n" + + c2 + " \n" + + "Obj 1 pointers:\n" + + this.bodyPointerMap.get(b1) + " \n" + + this.geomPointerMap.get(o1) + " \n" + + "Obj 2 pointers:\n" + + this.bodyPointerMap.get(b2) + " \n" + + this.geomPointerMap.get(o2) + " \n" + + "" + ; + throw new Error(message); + } + Globals.profiler.beginAggregateCpuSample("CollisionEngine.nearCallback - try collisions"); try { //creates a buffer to store potential collisions @@ -415,14 +487,20 @@ public class CollisionEngine { // //add contact to contact group DJoint c = OdeHelper.createContactJoint(world,contactgroup,contact); - c.attach(b1,b2); + if(b1 == null){ + c.attach(b2,null); + } else if(b2 == null){ + c.attach(b1,null); + } else { + c.attach(b1,b2); + } // Use the default collision resolution if(collisionResolutionCallback == null) { CollisionEngine.resolveCollision( contact.geom, - bodyPointerMap.get(o1.getBody()), - bodyPointerMap.get(o2.getBody()), + c1, + c2, PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0), PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0), PhysicsUtils.odeVecToJomlVec(contact.geom.pos), @@ -430,8 +508,8 @@ public class CollisionEngine { ); CollisionEngine.resolveCollision( contact.geom, - bodyPointerMap.get(o2.getBody()), - bodyPointerMap.get(o1.getBody()), + c1, + c2, PhysicsUtils.odeVecToJomlVec(contact.geom.normal), PhysicsUtils.odeVecToJomlVec(contact.fdir1), PhysicsUtils.odeVecToJomlVec(contact.geom.pos), @@ -443,8 +521,8 @@ public class CollisionEngine { contact.geom, o1, o2, - bodyPointerMap.get(o1.getBody()), - bodyPointerMap.get(o2.getBody()), + c1, + c2, PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0), PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0), PhysicsUtils.odeVecToJomlVec(contact.geom.pos), @@ -454,8 +532,8 @@ public class CollisionEngine { contact.geom, o2, o1, - bodyPointerMap.get(o2.getBody()), - bodyPointerMap.get(o1.getBody()), + c2, + c1, PhysicsUtils.odeVecToJomlVec(contact.geom.normal), PhysicsUtils.odeVecToJomlVec(contact.fdir1), PhysicsUtils.odeVecToJomlVec(contact.geom.pos), @@ -566,6 +644,14 @@ public class CollisionEngine { newRotation = PhysicsUtils.getRigidBodyRotation(rigidBody); } else { newRotation = PhysicsUtils.getGeomRotation(geom); + if(geom instanceof DCylinder || geom instanceof DCapsule){ + newRotation.rotateX(-Math.PI/2.0); + } + } + if(geom != null){ + CollidableTemplate template = PhysicsEntityUtils.getPhysicsTemplate(physicsEntity); + suggestedPosition.sub(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()); + newRotation.mul(new Quaterniond(template.getRotX(),template.getRotY(),template.getRotZ(),template.getRotW()).invert()); } EntityUtils.getPosition(physicsEntity).set(suggestedPosition); EntityUtils.getRotation(physicsEntity).set(newRotation); @@ -612,6 +698,11 @@ public class CollisionEngine { Vector3d existingPosition = PhysicsUtils.odeVecToJomlVec(rigidBody.getPosition()); rigidBody.setPosition(PhysicsUtils.jomlVecToOdeVec(existingPosition.add(delta))); } + DGeom geom = PhysicsEntityUtils.getDGeom(physicsEntity); + if(geom != null){ + Vector3d existingPosition = PhysicsUtils.odeVecToJomlVec(geom.getPosition()); + geom.setPosition(PhysicsUtils.jomlVecToOdeVec(existingPosition.add(delta))); + } } } spaceLock.unlock(); @@ -624,6 +715,9 @@ public class CollisionEngine { * @param collidable The corresponding collidable */ public void registerCollisionObject(DBody body, Collidable collidable){ + if(collidable == null){ + throw new Error("Collidable is null!"); + } spaceLock.lock(); this.registerPhysicsObject(body); bodyPointerMap.put(body,collidable); @@ -631,6 +725,21 @@ public class CollisionEngine { spaceLock.unlock(); } + /** + * Registers a collision object with the server + * @param geom The geom + * @param collidable The corresponding collidable + */ + public void registerCollisionObject(DGeom geom, Collidable collidable){ + if(collidable == null){ + throw new Error("Collidable is null!"); + } + spaceLock.lock(); + geomPointerMap.put(geom,collidable); + collidableList.add(collidable); + spaceLock.unlock(); + } + /** * Deregisters a collidable from the physics engine * @param collidable The collidable @@ -765,7 +874,6 @@ public class CollisionEngine { while(geomIterator.hasNext()){ DGeom geom = geomIterator.next(); space.remove(geom); - geom.DESTRUCTOR(); geom.destroy(); } //destroy all joints @@ -1102,8 +1210,12 @@ public class CollisionEngine { */ protected void setGeomTransform(DGeom geom, Vector3d position, Quaterniond rotation){ spaceLock.lock(); - geom.setPosition(position.x, position.y, position.z); - geom.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation)); + geom.setPosition(position.x - this.floatingOrigin.x, position.y - this.floatingOrigin.y, position.z - this.floatingOrigin.z); + if(geom instanceof DCylinder || geom instanceof DCapsule){ + geom.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(new Quaterniond(rotation).rotateX(Math.PI/2.0))); + } else { + geom.setQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation)); + } spaceLock.unlock(); } diff --git a/src/main/java/electrosphere/collision/PhysicsEntityUtils.java b/src/main/java/electrosphere/collision/PhysicsEntityUtils.java index 6abce99f..c759f5f6 100644 --- a/src/main/java/electrosphere/collision/PhysicsEntityUtils.java +++ b/src/main/java/electrosphere/collision/PhysicsEntityUtils.java @@ -58,8 +58,6 @@ public class PhysicsEntityUtils { * @param physicsTemplate The collidable template */ public static void clientAttachCollidableTemplate(Entity rVal, CollidableTemplate physicsTemplate){ - DBody rigidBody = null; - DGeom geom = null; Collidable collidable; double mass = 1.0f; CollisionEngine engine = Globals.clientState.clientSceneWrapper.getCollisionEngine(); @@ -71,6 +69,7 @@ public class PhysicsEntityUtils { categoryBit = Collidable.TYPE_STATIC_BIT; } if(physicsTemplate.getKinematic()){ + DGeom geom = null; switch(physicsTemplate.getType()){ case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: { @@ -97,8 +96,8 @@ public class PhysicsEntityUtils { rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); - Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable); Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE); + engine.registerCollisionObject(geom, collidable); } break; case CollidableTemplate.COLLIDABLE_TYPE_CUBE: { // @@ -125,8 +124,8 @@ public class PhysicsEntityUtils { rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable); Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE); + engine.registerCollisionObject(geom, collidable); } break; case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: { // @@ -156,11 +155,12 @@ public class PhysicsEntityUtils { rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); - Globals.clientState.clientSceneWrapper.getCollisionEngine().registerCollisionObject(rigidBody, collidable); Globals.clientState.clientScene.registerEntityToTag(rVal, EntityTags.COLLIDABLE); + engine.registerCollisionObject(geom, collidable); } break; } } else { + DBody rigidBody = null; switch(physicsTemplate.getType()){ case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: { @@ -359,10 +359,10 @@ public class PhysicsEntityUtils { 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 we successfully attached the body, add a sync tree + if(rigidBody != null){ + ClientPhysicsSyncTree.attachTree(rVal); + } } } @@ -374,7 +374,6 @@ public class PhysicsEntityUtils { * @param physicsTemplate The collidable template */ public static void serverAttachCollidableTemplate(Realm realm, Entity rVal, CollidableTemplate physicsTemplate){ - DBody rigidBody = null; Collidable collidable; double mass = 1.0f; if(physicsTemplate.getMass() != null){ @@ -384,208 +383,308 @@ public class PhysicsEntityUtils { if(physicsTemplate.getKinematic()){ categoryBit = Collidable.TYPE_STATIC_BIT; } - switch(physicsTemplate.getType()){ - case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: { + if(physicsTemplate.getKinematic()){ + DGeom geom = 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( + // + //create dbody + geom = CollisionBodyCreation.createCylinderShape( 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()) + categoryBit ); - } - 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); + PhysicsEntityUtils.setDGeom(rVal, geom); - // - //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 + ); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); + rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); + rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - // - //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()){ - 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.SERVER_COLLIDABLE_TREE, tree); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); - rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); - - realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); - 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( + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE); + realm.getCollisionEngine().registerCollisionObject(geom, collidable); + } break; + case CollidableTemplate.COLLIDABLE_TYPE_CUBE: { + // + //create dbody + geom = CollisionBodyCreation.createCubeShape( 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()) + categoryBit ); - } - 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); + PhysicsEntityUtils.setDGeom(rVal, geom); - // - //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 + ); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); + rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); + rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - // - //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()){ - 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.SERVER_COLLIDABLE_TREE, tree); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); - rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); - - realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); - 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( + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE); + realm.getCollisionEngine().registerCollisionObject(geom, collidable); + } break; + case CollidableTemplate.COLLIDABLE_TYPE_CAPSULE: { + // + //create dbody + geom = CollisionBodyCreation.createCapsuleShape( 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()) + categoryBit ); - } - 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); + PhysicsEntityUtils.setDGeom(rVal, geom); - // - //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 + ); + rVal.putData(EntityDataStrings.PHYSICS_COLLISION_BODY_TRANSFORM, offsetTransform); + rVal.putData(EntityDataStrings.PHYSICS_MODEL_TEMPLATE, physicsTemplate); + rVal.putData(EntityDataStrings.PHYSICS_COLLIDABLE, collidable); - // - //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()){ - 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.SERVER_COLLIDABLE_TREE, tree); + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); - rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + ServerEntityTagUtils.attachTagToEntity(rVal, EntityTags.COLLIDABLE); + realm.getCollisionEngine().registerCollisionObject(geom, collidable); + } break; + } + } else { + DBody rigidBody = null; + switch(physicsTemplate.getType()){ + case CollidableTemplate.COLLIDABLE_TYPE_CYLINDER: { - 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); + // + //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()){ + 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.SERVER_COLLIDABLE_TREE, tree); + + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + + realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + 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()){ + 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.SERVER_COLLIDABLE_TREE, tree); + + rVal.putData(EntityDataStrings.PHYSICS_MASS, mass); + + realm.getCollisionEngine().registerCollisionObject(rigidBody, collidable); + 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()){ + 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.SERVER_COLLIDABLE_TREE, tree); + + 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); + } } } diff --git a/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java b/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java index f209e3aa..c3f46a56 100644 --- a/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java +++ b/src/main/java/electrosphere/entity/types/collision/CollisionObjUtils.java @@ -9,6 +9,7 @@ import electrosphere.collision.CollisionEngine; import electrosphere.collision.PhysicsEntityUtils; import electrosphere.collision.PhysicsUtils; import electrosphere.collision.collidable.Collidable; +import electrosphere.data.entity.collidable.CollidableTemplate; import electrosphere.engine.Globals; import electrosphere.entity.Entity; import electrosphere.entity.EntityDataStrings; @@ -75,10 +76,20 @@ public class CollisionObjUtils { EntityUtils.getPosition(e).set(position); Quaterniond rotation = EntityUtils.getRotation(e); DBody body = PhysicsEntityUtils.getDBody(e); + DGeom geom = PhysicsEntityUtils.getDGeom(e); CollisionEngine collisionEngine = Globals.serverState.realmManager.getEntityRealm(e).getCollisionEngine(); if(body != null){ PhysicsUtils.setRigidBodyTransform(collisionEngine, position, rotation, body); } + if(geom != null){ + CollidableTemplate template = PhysicsEntityUtils.getPhysicsTemplate(e); + PhysicsUtils.setGeomTransform( + collisionEngine, + new Vector3d(position).add(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()), + rotation, + geom + ); + } } /** @@ -95,7 +106,13 @@ public class CollisionObjUtils { } DGeom geom = PhysicsEntityUtils.getDGeom(e); if(geom != null){ - PhysicsUtils.setGeomTransform(Globals.clientState.clientSceneWrapper.getCollisionEngine(), position, rotation, geom); + CollidableTemplate template = PhysicsEntityUtils.getPhysicsTemplate(e); + PhysicsUtils.setGeomTransform( + Globals.clientState.clientSceneWrapper.getCollisionEngine(), + new Vector3d(position).add(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()), + rotation, + geom + ); } } diff --git a/src/main/java/electrosphere/server/physics/collision/ServerHitboxResolutionCallback.java b/src/main/java/electrosphere/server/physics/collision/ServerHitboxResolutionCallback.java index 5a6c1bc4..8fbf8d97 100644 --- a/src/main/java/electrosphere/server/physics/collision/ServerHitboxResolutionCallback.java +++ b/src/main/java/electrosphere/server/physics/collision/ServerHitboxResolutionCallback.java @@ -33,43 +33,45 @@ public class ServerHitboxResolutionCallback implements CollisionResolutionCallba //basic error checking if(impactorEntity == null){ - throw new IllegalStateException("Impactor's entity is null"); + throw new Error("Impactor's entity is null"); } if(receiverEntity == null){ - throw new IllegalStateException("Receiver's entity is null"); + throw new Error("Receiver's entity is null"); } if(!HitboxCollectionState.hasHitboxState(impactorEntity)){ - throw new IllegalStateException("Impactor state is null"); + throw new Error("Impactor state is null"); } if(!HitboxCollectionState.hasHitboxState(receiverEntity)){ - throw new IllegalStateException("Receiver state is null"); + throw new Error("Receiver state is null"); } if(impactorGeom == null){ - throw new IllegalStateException("Impactor geom is null"); + throw new Error("Impactor geom is null"); } if(receiverGeom == null){ - throw new IllegalStateException("Receiver geom is null"); + throw new Error("Receiver geom is null"); } if(!impactorState.getGeometries().contains(impactorGeom)){ + boolean receiverStateContainsGeom = receiverState.getGeometries().contains(impactorGeom); String message = "Impactor geom has wrong parent assigned!\n" + "Problem geom: " + impactorGeom + "\n" + - "All geometries tracked: " + impactorState.getGeometries() + "n\"" + "All geometries tracked: " + impactorState.getGeometries() + "\n" + + "Receiver contains impactor: " + receiverStateContainsGeom + "\n" ; - throw new IllegalStateException(message); + throw new Error(message); } if(impactorShapeStatus == null){ String message = "Impactor shape status is null\n" + "Problem geom: " + impactorGeom + "\n" + "All geometries tracked: " + impactorState.getGeometries() + "n\"" ; - throw new IllegalStateException(message); + throw new Error(message); } if(receiverShapeStatus == null){ String message = "Receiver shape status is null\n" + "Problem geom: " + receiverGeom + "\n" + "All geometries tracked: " + receiverState.getGeometries() + "n\"" ; - throw new IllegalStateException(message); + throw new Error(message); } diff --git a/src/main/java/electrosphere/server/simulation/MicroSimulation.java b/src/main/java/electrosphere/server/simulation/MicroSimulation.java index 53758231..c67f1106 100644 --- a/src/main/java/electrosphere/server/simulation/MicroSimulation.java +++ b/src/main/java/electrosphere/server/simulation/MicroSimulation.java @@ -64,7 +64,9 @@ public class MicroSimulation { //sum collidable impulses Set collidables = dataCell.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE); for(Entity collidable : collidables){ - ServerCollidableTree.getServerCollidableTree(collidable).simulate((float)Globals.engineState.timekeeper.getSimFrameTime()); + if(ServerCollidableTree.hasServerCollidableTree(collidable)){ + ServerCollidableTree.getServerCollidableTree(collidable).simulate((float)Globals.engineState.timekeeper.getSimFrameTime()); + } } //update actor transform caches poseableEntities = dataCell.getScene().getEntitiesWithTag(EntityTags.POSEABLE);