work on moving hitboxes to ode4j handling

This commit is contained in:
austin 2024-06-07 17:50:49 -04:00
parent b1d79dbc16
commit a30ac75573
57 changed files with 1788 additions and 859 deletions

View File

@ -18,7 +18,8 @@
"renderResolutionX": 1920,
"renderResolutionY": 1080,
"graphicsDebugDrawCollisionSpheres" : false,
"graphicsDebugDrawCollisionSpheresClient" : false,
"graphicsDebugDrawCollisionSpheresServer" : false,
"graphicsDebugDrawPhysicsObjects" : false,
"graphicsDebugDrawMovementVectors" : false,
"graphicsDebugDrawNavmesh" : false,

View File

@ -5,32 +5,37 @@
"hitboxes" : [
{
"type": "hurt",
"bone": "Bone.031",
"bone": "Bicep.L",
"radius": 0.04
},
{
"type": "hurt",
"bone": "Bone.012",
"bone": "Bicep.R",
"radius": 0.04
},
{
"type": "hurt",
"bone": "Bone.003",
"bone": "Leg.L",
"radius": 0.04
},
{
"type": "hurt",
"bone": "Bone.010",
"bone": "Leg.R",
"radius": 0.04
},
{
"type": "hurt",
"bone": "Shoulder.L",
"radius": 0.06
},
{
"type": "hurt",
"bone": "Bone.001",
"bone": "Shoulder.R",
"radius": 0.06
},
{
"type": "hurt",
"bone": "Bone.014",
"bone": "Neck",
"radius": 0.06
},
{
@ -40,13 +45,8 @@
},
{
"type": "hurt",
"bone": "Bone.014",
"bone": "Head",
"radius": 0.06
},
{
"type": "hurt",
"bone": "Bone.019",
"radius": 0.04
}
],
"tokens" : [

Binary file not shown.

View File

@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file
#Sun May 19 19:34:37 EDT 2024
buildNumber=132
#Sat Jun 01 15:22:11 EDT 2024
buildNumber=134

View File

@ -310,14 +310,34 @@ Attaching items to hands in first person
Fix grass placement
(05/25/2024)
(05/26/2024)
VERY rudimentary first person documentation to give basic navigation to relevant files.
Fix attacking looping and freezing the character in place
- Was using delta real time (0.02ms) instead of delta frames in server and client attack trees (1 frame/simulate() call)
Document hitboxes
- Documented how it works currently and the architecture we want to move towards
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Need to have an object attached to creature that stores the rigid body
- When creating the creature, for each hitbox, create shapes for the rigid body
- Attach the overall object to the creature entity
(05/27/2024)
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Synchronize hitbox positions each frame
(05/31/2024)
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Write custom callback for the collision engine for just hitboxes
# TODO
Redo hitboxes to have capsules and also chaining between frames (but not between swinging the camera around)
- Introduce block hitbox (blockbox) type
Fix being able to walk off far side of the world (ie in level editor)
@ -349,6 +369,8 @@ More Debug menus
- Screen that shows the overall status of fluid cell manager
- Screen that shows the overall status of realm 0
- Screen that shows the overall status of realm manager
- Particularly, want a view of all entities in the scene, and the ability to click on a single entity to get an overview of everything on the entity
- For each behavior tree, ability to click into the tree and view fine details about its state (both pure state variable as well as other relevant variables)
Revisit first attempt at instancing (its really laggy lol)
- Maybe have draw call happen on top level entity and immediately queue all children recursively

View File

@ -310,6 +310,17 @@
"positionY",
"positionZ"
]
},
{
"messageName" : "updateEntityViewDir",
"data" : [
"entityID",
"time",
"positionX",
"positionY",
"positionZ",
"propertyValueInt"
]
}

View File

@ -1,19 +1,20 @@
package electrosphere.client.scene;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.joml.Vector3d;
import org.ode4j.ode.DContactGeom;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.CollisionEngine.CollisionResolutionCallback;
import electrosphere.collision.collidable.Collidable;
import electrosphere.collision.hitbox.HitboxManager;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.Scene;
import electrosphere.logger.LoggerInterface;
import electrosphere.server.terrain.manager.ServerTerrainChunk;
/**
* Wrapper around the scene object to provide lots of much needed client-specific utility
@ -31,9 +32,18 @@ public class ClientSceneWrapper {
//The engine used to back physics collision checks in client
CollisionEngine collisionEngine;
//The hitbox manager
HitboxManager hitboxManager;
/**
* Constructor
* @param scene The scene
* @param collisionEngine The collision engine
*/
public ClientSceneWrapper(Scene scene, CollisionEngine collisionEngine){
this.scene = scene;
this.collisionEngine = collisionEngine;
this.hitboxManager = new HitboxManager(resolutionCallback);
}
/**
@ -110,6 +120,14 @@ public class ClientSceneWrapper {
return collisionEngine;
}
/**
* Gets the hitbox manager for the client
* @return The hitbox manager
*/
public HitboxManager getHitboxManager(){
return hitboxManager;
}
/**
* Destroys all entities outside simulation range
*/
@ -129,4 +147,15 @@ public class ClientSceneWrapper {
Globals.profiler.endCpuSample();
}
/**
* The resolution callback that is invoked once a collision has occurred
*/
CollisionResolutionCallback resolutionCallback = new CollisionResolutionCallback() {
@Override
public void resolve(DContactGeom geom, Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude) {
HitboxUtils.clientDamageHitboxColision(impactor.getParent(), receiver.getParent());
}
};
}

View File

@ -6,11 +6,7 @@ import electrosphere.client.fluid.manager.ClientFluidManager;
import electrosphere.client.instancing.InstanceUpdater;
import electrosphere.client.targeting.crosshair.Crosshair;
import electrosphere.client.terrain.manager.ClientTerrainManager;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
@ -44,6 +40,7 @@ public class ClientSimulation {
public void simulate(){
Globals.profiler.beginCpuSample("simulate");
//
//load terrain
if(isLoadingTerrain()){
loadTerrain();
@ -53,10 +50,11 @@ public class ClientSimulation {
Globals.profiler.beginCpuSample("clientSynchronizationManager.processMessages");
Globals.clientSynchronizationManager.processMessages();
Globals.profiler.endCpuSample();
//
//simulate bullet physics engine step
Globals.clientSceneWrapper.getCollisionEngine().simulatePhysics((float)Globals.timekeeper.getSimFrameTime());
Globals.clientSceneWrapper.getCollisionEngine().updateDynamicObjectTransforms();
//
//update actor animations
Globals.profiler.beginCpuSample("update actor animations");
for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.DRAWABLE)){
@ -66,12 +64,14 @@ public class ClientSimulation {
}
}
Globals.profiler.endCpuSample();
//
//make items play idle animation
Globals.profiler.beginCpuSample("item animations");
for(Entity item : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.ITEM)){
ItemUtils.updateItemActorAnimation(item);
}
Globals.profiler.endCpuSample();
//
//particle state updates
Globals.profiler.beginCpuSample("particle state updates");
for(Entity particle : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.PARTICLE)){
@ -80,18 +80,12 @@ public class ClientSimulation {
Globals.profiler.endCpuSample();
//update attached entity positions
AttachUtils.clientUpdateAttachedEntityPositions();
//update hitbox positions
Globals.profiler.beginCpuSample("Hitbox updates");
for(Entity currentHitbox : Globals.clientHitboxManager.getAllHitboxes()){
HitboxUtils.clientUpdatePosition(currentHitbox);
}
//collide hitboxes
for(Entity currentHitbox : Globals.clientHitboxManager.getAllHitboxes()){
if(isReady){
HitboxUtils.clientCollideEntities(currentHitbox);
}
}
//
//Hitbox stuff
Globals.profiler.beginCpuSample("update hitboxes");
Globals.clientSceneWrapper.getHitboxManager().simulate();
Globals.profiler.endCpuSample();
//
//update audio engine
Globals.profiler.beginCpuSample("audio engine update");
if(Globals.audioEngine!=null){
@ -99,31 +93,32 @@ public class ClientSimulation {
Globals.virtualAudioSourceManager.update((float)Globals.timekeeper.getSimFrameTime());
}
Globals.profiler.endCpuSample();
//
//update foliage
if(Globals.clientFoliageManager != null){
Globals.clientFoliageManager.update();
}
//tally collidables and offset position accordingly
// for(Entity currentCollidable : Globals.entityManager.getEntitiesWithTag(EntityTags.COLLIDABLE)){
// CollidableTree tree = CollidableTree.getCollidableTree(currentCollidable);
// tree.simulate(Main.deltaFrames);
// }
//
//targeting crosshair
Globals.profiler.beginCpuSample("crosshair update");
Crosshair.checkTargetable();
Crosshair.updateTargetCrosshairPosition();
Globals.profiler.endCpuSample();
//
//simulate behavior trees
Globals.clientSceneWrapper.getScene().simulateBehaviorTrees((float)Globals.timekeeper.getSimFrameTime());
//
//sum collidable impulses
Globals.profiler.beginCpuSample("collidable logic");
for(Entity collidable : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.COLLIDABLE)){
ClientCollidableTree.getClientCollidableTree(collidable).simulate((float)Globals.timekeeper.getSimFrameTime());
}
//
//clear collidable impulse lists
Globals.clientSceneWrapper.getCollisionEngine().clearCollidableImpulseLists();
Globals.profiler.endCpuSample();
//
//wrap up functions
runClientFunctions();

View File

@ -12,9 +12,9 @@ import org.ode4j.math.DMatrix3;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DBox;
import org.ode4j.ode.DCylinder;
import org.ode4j.ode.DGeom;
import org.ode4j.ode.DSphere;
import org.ode4j.ode.DTriMesh;
import org.ode4j.ode.OdeHelper;
import electrosphere.entity.types.terrain.TerrainChunkData;
@ -81,6 +81,26 @@ public class CollisionBodyCreation {
return collisionEngine.createDBody(geom);
}
/**
* Creates a dbody with existing shapes that are provided
* @param collisionEngine the collision engine to create it in
* @param geoms the geometries to attach
* @return the dbody
*/
public static DBody createBodyWithShapes(CollisionEngine collisionEngine, DGeom ... geoms){
return collisionEngine.createDBody(geoms);
}
/**
* Creates a sphere shape
* @param collisionEngine the collision engine
* @param radius the radius of the sphere
* @return the sphere shape
*/
public static DSphere createShapeSphere(CollisionEngine collisionEngine, double radius, long categoryBits){
return collisionEngine.createSphereGeom(radius, categoryBits);
}
/**
* Sets the provided body to be a kinematic body (no gravity applied)
* @param collisionEngine The collision engine
@ -154,7 +174,7 @@ public class CollisionBodyCreation {
*/
public static DBody generateRigidBodyFromAIScene(CollisionEngine collisionEngine, AIScene scene, long categoryBits){
DBody body = collisionEngine.createDBody(null);
DBody body = collisionEngine.createDBody((DGeom[])null);
PointerBuffer meshesBuffer = scene.mMeshes();
while(meshesBuffer.hasRemaining()){

View File

@ -31,6 +31,7 @@ import org.ode4j.ode.DBox;
import org.ode4j.ode.DCapsule;
import org.ode4j.ode.DContact;
import org.ode4j.ode.DContactBuffer;
import org.ode4j.ode.DContactGeom;
import org.ode4j.ode.DContactJoint;
import org.ode4j.ode.DCylinder;
import org.ode4j.ode.DGeom;
@ -50,6 +51,7 @@ import org.ode4j.ode.OdeHelper;
import electrosphere.collision.RayCastCallback.RayCastCallbackData;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals;
import electrosphere.engine.time.Timekeeper;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
@ -63,9 +65,6 @@ import electrosphere.logger.LoggerInterface;
*/
public class CollisionEngine {
//step interval time size
public static final float ENGINE_STEP_SIZE = 0.01f;
//gravity constant
public static final float GRAVITY_MAGNITUDE = 9.8f * 2;
@ -91,16 +90,44 @@ public class CollisionEngine {
//callbacks for collision check
RayCastCallback rayCastCallback = new RayCastCallback();
//the collision resolution callback
CollisionResolutionCallback collisionResolutionCallback;
//buffer for collisions
DContactBuffer contacts = null;
// Callback for any near collisions in the broadphase of the collision check
private DNearCallback nearCallback;
/**
* Constructor
*/
public CollisionEngine(){
world = OdeHelper.createWorld();
space = OdeHelper.createBHVSpace(Collidable.TYPE_STATIC_BIT);
world.setGravity(0,-GRAVITY_MAGNITUDE,0);
contactgroup = OdeHelper.createJointGroup();
this.nearCallback = new DNearCallback() {
@Override
public void call(Object data, DGeom o1, DGeom o2) {
nearCallback( data, o1, o2);
}
};
}
public static void resolveCollision(Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude){
/**
* Resolves collisions in the engine
* @param contactGeom the ode4j contact geometry
* @param impactor the instigator of the collision
* @param receiver the receiver of the collision
* @param normal the normal to the collision surface
* @param localPosition the local position of the collision
* @param worldPos the world position of the collision
* @param magnitude the magnitude of the collision
*/
public static void resolveCollision(DContactGeom contactGeom, Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude){
switch(receiver.getType()){
case Collidable.TYPE_CREATURE:
switch(impactor.getType()){
@ -223,7 +250,7 @@ public class CollisionEngine {
//simulate physics
Globals.profiler.beginCpuSample("step physics");
world.quickStep(ENGINE_STEP_SIZE);
world.quickStep(Timekeeper.ENGINE_STEP_SIZE);
Globals.profiler.endCpuSample();
// remove all contact joints
@ -233,27 +260,45 @@ public class CollisionEngine {
}
/**
* Callback for any near collisions in the broadphase of the collision check
* Runs a collision cycle on all bodies in the collision engine
*/
private DNearCallback nearCallback = new DNearCallback() {
@Override
public void call(Object data, DGeom o1, DGeom o2) {
nearCallback( data, o1, o2);
}
};
public void collide(){
Globals.profiler.beginCpuSample("physics");
spaceLock.acquireUninterruptibly();
Globals.profiler.beginCpuSample("collide");
OdeHelper.spaceCollide(space, 0, nearCallback);
Globals.profiler.endCpuSample();
//buffer for collisions
DContactBuffer contacts = null;
// remove all contact joints
contactgroup.empty();
spaceLock.release();
Globals.profiler.endCpuSample();
}
// this is called by dSpaceCollide when two objects in space are
// potentially colliding.
/**
* Sets the near callback function for all collision calls.
* !!YOU LIKELY WANT TO INSTEAD OVERWRITE THE CollisionResolutionCallback!!
* @param callback the callback
*/
public void setNearCallback(DNearCallback callback){
this.nearCallback = callback;
}
/**
* This is called by dSpaceCollide when two objects in space are potentially colliding.
* @param data The data
* @param o1 the first collision body
* @param o2 the second collision body
*/
private void nearCallback (Object data, DGeom o1, DGeom o2) {
// if (o1->body && o2->body) return;
// exit without doing anything if the two bodies are connected by a joint
DBody b1 = o1.getBody();
DBody b2 = o2.getBody();
if (b1!=null && b2!=null && areConnectedExcluding (b1,b2,DContactJoint.class)) return;
if (b1!=null && b2!=null && areConnectedExcluding (b1,b2,DContactJoint.class)){
return;
}
//creates a buffer to store potential collisions
DContactBuffer contacts = new DContactBuffer(MAX_CONTACTS); // up to MAX_CONTACTS contacts per box-box
@ -284,33 +329,51 @@ public class CollisionEngine {
DContact contact = contacts.get(i);
//special code for ray casting
if (o1 instanceof DRay || o2 instanceof DRay){
DMatrix3 Rotation = new DMatrix3();
Rotation.setIdentity();
// dsDrawSphere(contact.geom.pos, Rotation, (0.01));
DVector3 End = new DVector3();
End.eqSum( contact.geom.pos, contact.geom.normal, contact.geom.depth );
// dsDrawLine(contact.geom.pos, End);
DVector3 end = new DVector3();
end.eqSum( contact.geom.pos, contact.geom.normal, contact.geom.depth );
continue;
}
// contact.geom.pos
resolveCollision(
bodyPointerMap.get(o1.getBody()),
bodyPointerMap.get(o2.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
// Use the default collision resolution
if(collisionResolutionCallback == null) {
resolveCollision(
contact.geom,
bodyPointerMap.get(o1.getBody()),
bodyPointerMap.get(o2.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
);
resolveCollision(
contact.geom,
bodyPointerMap.get(o2.getBody()),
bodyPointerMap.get(o1.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.normal),
PhysicsUtils.odeVecToJomlVec(contact.fdir1),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
);
} else {
//use custom collision resolution
collisionResolutionCallback.resolve(
contact.geom,
bodyPointerMap.get(o1.getBody()),
bodyPointerMap.get(o2.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.normal).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.fdir1).mul(-1.0),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
);
resolveCollision(
bodyPointerMap.get(o2.getBody()),
bodyPointerMap.get(o1.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.normal),
PhysicsUtils.odeVecToJomlVec(contact.fdir1),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
collisionResolutionCallback.resolve(
contact.geom,
bodyPointerMap.get(o2.getBody()),
bodyPointerMap.get(o1.getBody()),
PhysicsUtils.odeVecToJomlVec(contact.geom.normal),
PhysicsUtils.odeVecToJomlVec(contact.fdir1),
PhysicsUtils.odeVecToJomlVec(contact.geom.pos),
(float)contact.geom.depth
);
}
//add contact to contact group
DJoint c = OdeHelper.createContactJoint (world,contactgroup,contact );
@ -325,6 +388,14 @@ public class CollisionEngine {
}
}
}
/**
* Sets the function that is called once a collision has happened
* @param collisionResolutionCallback the function
*/
public void setCollisionResolutionCallback(CollisionResolutionCallback collisionResolutionCallback){
this.collisionResolutionCallback = collisionResolutionCallback;
}
/**
*
@ -691,6 +762,19 @@ public class CollisionEngine {
spaceLock.release();
}
/**
* Sets the transform of a geometry
* @param geom The geometry
* @param position The position
* @param rotation The rotation
*/
protected void setGeomTransform(DGeom geom, Vector3d position, Quaterniond rotation){
spaceLock.acquireUninterruptibly();
geom.setOffsetWorldPosition(position.x, position.y, position.z);
geom.setOffsetQuaternion(PhysicsUtils.jomlQuatToOdeQuat(rotation));
spaceLock.release();
}
/**
* Corrects the initial axis of eg cylinders or capsules
* @param geom the geometry to correct
@ -759,4 +843,22 @@ public class CollisionEngine {
spaceLock.release();
}
/**
* A callback for resolving collisions between two entities
*/
public interface CollisionResolutionCallback {
/**
* Resolves a collision between two collidables in the engine
* @param contactGeom the ode4j contact geom
* @param impactor The collidable initiating the contact
* @param receiver The collidable recieving the contact
* @param normal The normal of the collision
* @param localPosition The local position of the collision
* @param worldPos The world position of the collision
* @param magnitude The magnitude of the collision
*/
public void resolve(DContactGeom contactGeom, Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude);
}
}

View File

@ -2,10 +2,12 @@ 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.DCylinder;
import org.ode4j.ode.DGeom;
import org.ode4j.ode.DTriMesh;
import electrosphere.collision.collidable.Collidable;
@ -301,5 +303,14 @@ public class PhysicsEntityUtils {
public static DBody getDBody(Entity entity){
return (DBody)entity.getData(EntityDataStrings.PHYSICS_COLLISION_BODY);
}
/**
* Sets the position of a DGeom
* @param collisionEngine the collision engine
* @param geom the geometry
*/
public static void setGeometryPosition(CollisionEngine collisionEngine, DGeom geom, Vector3d position, Quaterniond rotation){
collisionEngine.setGeomTransform(geom, position, rotation);
}
}

View File

@ -39,7 +39,15 @@ public class PhysicsUtils {
*/
public static Vector3d odeVecToJomlVec(org.ode4j.math.DVector3C vector){
return new Vector3d(vector.get0(),vector.get1(),vector.get2());
}
/**
* Converts a joml vector to an Ode vector
* @param vector joml vector
* @return Ode vector
*/
public static org.ode4j.math.DVector3C jomlVecToOdeVec(Vector3d vector){
return new org.ode4j.math.DVector3(vector.x,vector.y,vector.z);
}
/**

View File

@ -1,8 +1,9 @@
package electrosphere.collision.hitbox;
import electrosphere.collision.CollisionEngine;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.collision.CollisionEngine.CollisionResolutionCallback;
import electrosphere.engine.Globals;
import electrosphere.entity.state.hitbox.HitboxState;
import java.util.concurrent.CopyOnWriteArrayList;
/**
@ -11,7 +12,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
public class HitboxManager {
//the list of all hitboxes
CopyOnWriteArrayList<Entity> hitboxes = new CopyOnWriteArrayList<Entity>();
CopyOnWriteArrayList<HitboxState> hitboxes = new CopyOnWriteArrayList<HitboxState>();
//the collision engine for this hitbox manager
CollisionEngine collisionEngine;
@ -21,26 +22,27 @@ public class HitboxManager {
/**
* Constructor
* @param resolutionCallback The callback that fires when a collision occurs
*/
public HitboxManager(){
public HitboxManager(CollisionResolutionCallback resolutionCallback){
collisionEngine = new CollisionEngine();
collisionEngine.setCollisionResolutionCallback(resolutionCallback);
}
/**
* Registers a hitbox to the manager
* @param hitbox the hitbox to register
*/
public void registerHitbox(Entity hitbox){
public void registerHitbox(HitboxState hitbox){
hitboxes.add(hitbox);
idIncrementer++;
hitbox.putData(EntityDataStrings.COLLISION_ENTITY_ID, idIncrementer);
}
/**
* Gets all hitboxes in the manager
* @return all hitboxes in the manager
*/
public CopyOnWriteArrayList<Entity> getAllHitboxes(){
public CopyOnWriteArrayList<HitboxState> getAllHitboxes(){
return hitboxes;
}
@ -48,7 +50,35 @@ public class HitboxManager {
* Deregisters a hitbox from the manager
* @param hitbox the hitbox to deregister
*/
public void deregisterHitbox(Entity hitbox){
public void deregisterHitbox(HitboxState hitbox){
hitboxes.remove(hitbox);
}
/**
* Gets the collision engine associated with the hitbox manager
* @return The collision engine
*/
public CollisionEngine getCollisionEngine(){
return this.collisionEngine;
}
/**
* Runs all per frame functions of the hitbox manager
*/
public void simulate(){
//update all positions
Globals.profiler.beginCpuSample("Update hitbox positions");
for(HitboxState state : hitboxes){
state.updateHitboxPositions(this.collisionEngine);
}
Globals.profiler.endCpuSample();
//collide hitboxes
Globals.profiler.beginCpuSample("Collide hitboxes");
this.collisionEngine.collide();
this.collisionEngine.clearCollidableImpulseLists();
Globals.profiler.endCpuSample();
}
}

View File

@ -26,153 +26,153 @@ import org.joml.Vector3f;
*/
public class HitboxUtils {
/**
* Spawns a hitbox entity on the client
* @param parent The parent entity to attach the hitbox to
* @param bone The bone on the parent to attach to
* @param size The radius of the hitsphere
* @return The hitbox entity
*/
public static Entity clientSpawnRegularHitbox(Entity parent, String bone, float size){
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
HitboxData data = new HitboxData();
data.setActive(false);
data.setBone(bone);
data.setRadius(size);
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.clientHitboxManager.registerHitbox(rVal);
return rVal;
}
// /**
// * Spawns a hitbox entity on the client
// * @param parent The parent entity to attach the hitbox to
// * @param bone The bone on the parent to attach to
// * @param size The radius of the hitsphere
// * @return The hitbox entity
// */
// public static Entity clientSpawnRegularHitbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// HitboxData data = new HitboxData();
// data.setActive(false);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.clientHitboxManager.registerHitbox(rVal);
// return rVal;
// }
/**
* Spawns a hitbox entity on the server
* @param parent The parent entity to attach the hitbox to
* @param bone The bone to attach to the hitbox to
* @param size The radius of the hitsphere
* @return The hitbox entity
*/
public static Entity serverSpawnRegularHitbox(Entity parent, String bone, float size){
Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
HitboxData data = new HitboxData();
data.setActive(false);
data.setBone(bone);
data.setRadius(size);
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
return rVal;
}
// /**
// * Spawns a hitbox entity on the server
// * @param parent The parent entity to attach the hitbox to
// * @param bone The bone to attach to the hitbox to
// * @param size The radius of the hitsphere
// * @return The hitbox entity
// */
// public static Entity serverSpawnRegularHitbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
// HitboxData data = new HitboxData();
// data.setActive(false);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
// return rVal;
// }
/**
* Spawns a hurtbox on the client
* @param parent The parent entity of the hurtbox
* @param bone The bone on the parent to attach the hurtbox to
* @param size The radius of the hurtsphere
* @return The hurtbox entity
*/
public static Entity clientSpawnRegularHurtbox(Entity parent, String bone, float size){
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
HitboxData data = new HitboxData();
data.setActive(true);
data.setBone(bone);
data.setRadius(size);
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.clientHitboxManager.registerHitbox(rVal);
return rVal;
}
// /**
// * Spawns a hurtbox on the client
// * @param parent The parent entity of the hurtbox
// * @param bone The bone on the parent to attach the hurtbox to
// * @param size The radius of the hurtsphere
// * @return The hurtbox entity
// */
// public static Entity clientSpawnRegularHurtbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.clientHitboxManager.registerHitbox(rVal);
// return rVal;
// }
/**
* Spawns a hurtbox on the server
* @param parent The parent entity of the hurtbox
* @param bone The bone on the parent to attach the hurtbox to
* @param size The radius of the hurtsphere
* @return The hurtbox entity
*/
public static Entity serverSpawnRegularHurtbox(Entity parent, String bone, float size){
Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
HitboxData data = new HitboxData();
data.setActive(true);
data.setBone(bone);
data.setRadius(size);
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
return rVal;
}
// /**
// * Spawns a hurtbox on the server
// * @param parent The parent entity of the hurtbox
// * @param bone The bone on the parent to attach the hurtbox to
// * @param size The radius of the hurtsphere
// * @return The hurtbox entity
// */
// public static Entity serverSpawnRegularHurtbox(Entity parent, String bone, float size){
// Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setBone(bone);
// data.setRadius(size);
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
// return rVal;
// }
/**
* More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
* @param parent The parent entity of the hitbox
* @param positionCallback The position callback for keeping hitbox entity position up to date
* @param size The size of the hitbox
* @param hurtbox If true, it will instead be a hurtbox
* @param filter an optional list of parent entities to not colide with
* @return The hitbox entity
*/
public static Entity clientSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
Entity rVal = EntityCreationUtils.createClientSpatialEntity();
HitboxData data = new HitboxData();
data.setActive(true);
data.setPositionCallback(positionCallback);
data.setRadius(size);
data.setEntityFilter(filter);
if(hurtbox){
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
} else {
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
}
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.clientHitboxManager.registerHitbox(rVal);
return rVal;
}
// /**
// * More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
// * @param parent The parent entity of the hitbox
// * @param positionCallback The position callback for keeping hitbox entity position up to date
// * @param size The size of the hitbox
// * @param hurtbox If true, it will instead be a hurtbox
// * @param filter an optional list of parent entities to not colide with
// * @return The hitbox entity
// */
// public static Entity clientSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
// Entity rVal = EntityCreationUtils.createClientSpatialEntity();
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setPositionCallback(positionCallback);
// data.setRadius(size);
// data.setEntityFilter(filter);
// if(hurtbox){
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// } else {
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// }
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.clientHitboxManager.registerHitbox(rVal);
// return rVal;
// }
/**
* More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
* @param parent The parent entity of the hitbox
* @param positionCallback The position callback for keeping hitbox entity position up to date
* @param size The size of the hitbox
* @param hurtbox If true, it will instead be a hurtbox
* @param filter an optional list of parent entities to not colide with
* @return The hitbox entity
*/
public static Entity serverSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
HitboxData data = new HitboxData();
data.setActive(true);
data.setPositionCallback(positionCallback);
data.setRadius(size);
data.setEntityFilter(filter);
if(hurtbox){
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
} else {
data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
}
rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
rVal.putData(EntityDataStrings.HITBOX_DATA, data);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
return rVal;
}
// /**
// * More sophisticated function for spawning in hitboxes. Takes a position callback so it's not tied to a bone
// * @param parent The parent entity of the hitbox
// * @param positionCallback The position callback for keeping hitbox entity position up to date
// * @param size The size of the hitbox
// * @param hurtbox If true, it will instead be a hurtbox
// * @param filter an optional list of parent entities to not colide with
// * @return The hitbox entity
// */
// public static Entity serverSpawnRegularHitbox(Entity parent, HitboxPositionCallback positionCallback, float size, boolean hurtbox, List<Entity> filter){
// Entity rVal = EntityCreationUtils.createServerEntity(Globals.realmManager.getEntityRealm(parent), new Vector3d(0,0,0));
// HitboxData data = new HitboxData();
// data.setActive(true);
// data.setPositionCallback(positionCallback);
// data.setRadius(size);
// data.setEntityFilter(filter);
// if(hurtbox){
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT);
// } else {
// data.setType(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT);
// }
// rVal.putData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT, parent);
// rVal.putData(EntityDataStrings.HITBOX_DATA, data);
// rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
// rVal.putData(EntityDataStrings.DATA_STRING_DRAW, true);
// Globals.realmManager.getEntityRealm(parent).getHitboxManager().registerHitbox(rVal);
// return rVal;
// }
public static void clientUpdatePosition(Entity hitbox){
Entity parent = ((Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT));
@ -232,210 +232,48 @@ public class HitboxUtils {
}
}
/**
* Collides entities on the client
* @param generatorHitbox the hitbox generating the collision
*/
public static void clientCollideEntities(Entity generatorHitbox){
// long generatorId = (Long)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_ID);
//This is the entity the hitbox is attached to
Entity generatorParent = (Entity)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
for(Entity receiverHitbox : Globals.clientHitboxManager.getAllHitboxes()){
Entity receiverParent = (Entity)receiverHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
HitboxData generatorData = getHitboxData(generatorHitbox);
HitboxData receiverData = getHitboxData(receiverHitbox);
//check projectile filters
List<Entity> generatorFilter = generatorData.getEntityFilter();
if(generatorFilter != null && generatorFilter.contains(receiverParent)){
continue;
}
List<Entity> receiverFilter = receiverData.getEntityFilter();
if(receiverFilter != null && receiverFilter.contains(generatorParent)){
continue;
}
//if there is a collision
//and the collision isn't against itself
//and both hitboxes are active
if(
receiverParent != generatorParent &&
Globals.clientSceneWrapper.getCollisionEngine().collisionSphereCheck(generatorHitbox, generatorData, receiverHitbox, receiverData) &&
generatorData.isActive() &&
receiverData.isActive()){
//if two spheres collide, grab their hitbox types (eg hurt, hit, fire, etc)
String generatorType = generatorData.getType();
String receiverType = receiverData.getType();
if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){
clientDamageHitboxColision(generatorHitbox, receiverHitbox);
}
if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){
clientDamageHitboxColision(receiverHitbox, generatorHitbox);
}
}
}
}
/**
* Handles collision between two hitboxes on the server
* @param generatorHitbox the hitbox generating the collision
*/
public static void serverCollideEntities(Entity generatorHitbox){
// long generatorId = (Long)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_ID);
//This is the entity the hitbox is attached to
Entity generatorParent = (Entity)generatorHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
Realm generatorRealm = Globals.realmManager.getEntityRealm(generatorParent);
if(generatorRealm != null){
HitboxManager realmHitboxManager = generatorRealm.getHitboxManager();
for(Entity receiverHitbox : realmHitboxManager.getAllHitboxes()){
Entity receiverParent = (Entity)receiverHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
HitboxData generatorData = getHitboxData(generatorHitbox);
HitboxData receiverData = getHitboxData(receiverHitbox);
//check projectile filters
List<Entity> generatorFilter = generatorData.getEntityFilter();
if(generatorFilter != null && generatorFilter.contains(receiverParent)){
continue;
}
List<Entity> receiverFilter = receiverData.getEntityFilter();
if(receiverFilter != null && receiverFilter.contains(generatorParent)){
continue;
}
//if there is a collision
//and the collision isn't against itself
//and both hitboxes are active
if(
receiverParent != generatorParent &&
generatorRealm.getCollisionEngine().collisionSphereCheck(generatorHitbox, generatorData, receiverHitbox, receiverData) &&
generatorData.isActive() &&
receiverData.isActive()){
//if two spheres collide, grab their hitbox types (eg hurt, hit, fire, etc)
String generatorType = generatorData.getType();
String receiverType = receiverData.getType();
if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){
serverDamageHitboxColision(generatorHitbox, receiverHitbox);
}
if(generatorType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT) && receiverType.equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){
serverDamageHitboxColision(receiverHitbox, generatorHitbox);
}
}
}
}
}
/**
* Handles a damage collision on the client
* @param hitbox the hitbox
* @param hurtbox the hurtbox
* @param impactor the entity initiating the collision
* @param receiver the entity receiving the collision
*/
public static void clientDamageHitboxColision(Entity hitbox, Entity hurtbox){
public static void clientDamageHitboxColision(Entity impactor, Entity receiver){
Entity hitboxParent = (Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
Entity hurtboxParent = (Entity)hurtbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
// Entity hitboxParent = (Entity)impactor.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
// Entity hurtboxParent = (Entity)receiver.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
//if the entity is attached to is an item, we need to compare with the parent of the item
//to make sure you don't stab yourself for instance
boolean isItem = ItemUtils.isItem(hitboxParent);//hitboxParent.containsKey(EntityDataStrings.ITEM_IS_ITEM);
Entity hitboxAttachParent = AttachUtils.getParent(hitboxParent);
// boolean isItem = ItemUtils.isItem(hitboxParent);//hitboxParent.containsKey(EntityDataStrings.ITEM_IS_ITEM);
// Entity hitboxAttachParent = AttachUtils.getParent(hitboxParent);
if(isItem){
if(hitboxAttachParent != hurtboxParent){
LifeState lifeState = LifeUtils.getLifeState(hurtboxParent);
int currentHp = lifeState.getLifeCurrent();
int damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
LifeUtils.getLifeState(hurtboxParent).damage(damage);
if(currentHp > lifeState.getLifeCurrent()){
Vector3d hurtboxPos = EntityUtils.getPosition(hurtbox);
ParticleEffects.spawnBloodsplats(new Vector3f((float)hurtboxPos.x,(float)hurtboxPos.y,(float)hurtboxPos.z).add(0,0.1f,0), 20, 40);
}
if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(hurtboxParent).revive();
}
}
} else {
int damage = 0;
//for entities using attacktree
if(CreatureUtils.clientGetAttackTree(hitboxParent) != null){
damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
} else {
//for entities using shooter tree
if(ProjectileTree.getProjectileTree(hitboxParent) != null){
damage = (int)ProjectileTree.getProjectileTree(hitboxParent).getDamage();
}
}
LifeUtils.getLifeState(hurtboxParent).damage(damage);
if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(hurtboxParent).revive();
}
}
}
// if(isItem){
// if(hitboxAttachParent != hurtboxParent){
// Vector3d hurtboxPos = EntityUtils.getPosition(receiver);
// ParticleEffects.spawnBloodsplats(new Vector3f((float)hurtboxPos.x,(float)hurtboxPos.y,(float)hurtboxPos.z).add(0,0.1f,0), 20, 40);
// }
// } else {
/**
* Handles a damage hitbox collision on the server
* @param hitbox the hitbox
* @param hurtbox the hurtbox
*/
public static void serverDamageHitboxColision(Entity hitbox, Entity hurtbox){
Entity hitboxParent = (Entity)hitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
Entity hurtboxParent = (Entity)hurtbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_PARENT);
//if the entity is attached to is an item, we need to compare with the parent of the item
//to make sure you don't stab yourself for instance
boolean isItem = ItemUtils.isItem(hitboxParent);//hitboxParent.containsKey(EntityDataStrings.ITEM_IS_ITEM);
Entity hitboxAttachParent = AttachUtils.getParent(hitboxParent);
if(isItem){
if(hitboxAttachParent != hurtboxParent){
LifeState lifeState = LifeUtils.getLifeState(hurtboxParent);
int currentHp = lifeState.getLifeCurrent();
int damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
LifeUtils.getLifeState(hurtboxParent).damage(damage);
if(currentHp > lifeState.getLifeCurrent()){
Vector3d hurtboxPos = EntityUtils.getPosition(hurtbox);
ParticleEffects.spawnBloodsplats(new Vector3f((float)hurtboxPos.x,(float)hurtboxPos.y,(float)hurtboxPos.z).add(0,0.1f,0), 20, 40);
}
if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(hurtboxParent).revive();
}
}
} else {
int damage = 0;
//for entities using attacktree
if(CreatureUtils.serverGetAttackTree(hitboxParent) != null){
damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
} else {
//for entities using shooter tree
if(ProjectileTree.getProjectileTree(hitboxParent) != null){
damage = (int)ProjectileTree.getProjectileTree(hitboxParent).getDamage();
}
}
LifeUtils.getLifeState(hurtboxParent).damage(damage);
if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(hurtboxParent).revive();
}
}
// //client no longer manages damage; however, keeping this code around for the moment to show how we
// //might approach adding client-side effects as soon as impact occurs (ie play a sound, shoot sparks, etc)
// //before the server responds with a valid collision event or not
// // int damage = 0;
// // //for entities using attacktree
// // if(CreatureUtils.clientGetAttackTree(hitboxParent) != null){
// // damage = ItemUtils.getWeaponDataRaw(hitboxParent).getDamage();
// // } else {
// // //for entities using shooter tree
// // if(ProjectileTree.getProjectileTree(hitboxParent) != null){
// // damage = (int)ProjectileTree.getProjectileTree(hitboxParent).getDamage();
// // }
// // }
// // LifeUtils.getLifeState(hurtboxParent).damage(damage);
// // if(!LifeUtils.getLifeState(hurtboxParent).isIsAlive()){
// // EntityUtils.getPosition(hurtboxParent).set(Globals.spawnPoint);
// // LifeUtils.getLifeState(hurtboxParent).revive();
// // }
// }
}
/**
@ -447,24 +285,6 @@ public class HitboxUtils {
return (HitboxData)e.getData(EntityDataStrings.HITBOX_DATA);
}
/**
* Gets the hitbox associated list
* @param e The entity that has hitboxes
* @return the list of hitboxes associated with the entity
*/
public static List<Entity> getHitboxAssociatedList(Entity e){
return (List<Entity>)e.getData(EntityDataStrings.HITBOX_ASSOCIATED_LIST);
}
/**
* Gets the hurtbox associated list
* @param e the entity that has hurtboxes
* @return the list of hurtboxes associated with the entity
*/
public static List<Entity> getHurtboxAssociatedList(Entity e){
return (List<Entity>)e.getData(EntityDataStrings.HURTBOX_ASSOCIATED_LIST);
}
/**
* Intended to be implemented as an anonoymous class when needed
*/

View File

@ -10,6 +10,7 @@ import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.renderer.ui.events.MouseEvent;
public class CameraHandler {
@ -107,8 +108,21 @@ public class CameraHandler {
cameraRotationVector.mul(CameraEntityUtils.getOrbitalCameraDistance(Globals.playerCamera));
CameraEntityUtils.setCameraEye(Globals.playerCamera, cameraRotationVector);
//tell the server that we changed where we're looking
Globals.clientConnection.queueOutgoingMessage(
EntityMessage.constructupdateEntityViewDirMessage(
Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId()),
Globals.timekeeper.getNumberOfSimFramesElapsed(),
cameraRotationVector.x,
cameraRotationVector.y,
cameraRotationVector.z
)
);
//the view matrix
Globals.viewMatrix = CameraEntityUtils.getCameraViewMatrix(Globals.playerCamera);
//update the cursor on client side
updatePlayerCursor();
}
Globals.profiler.endCpuSample();

View File

@ -84,6 +84,11 @@ import electrosphere.util.FileUtils;
* @author amaterasu
*/
public class Globals {
//
//Process data
//
public static String javaPID;
//
//Top level user settings object
@ -302,9 +307,6 @@ public class Globals {
//script engine
public static ScriptEngine scriptEngine;
//manages hitboxes
public static HitboxManager clientHitboxManager;
//client scene management
public static Scene clientScene;
public static ClientSceneWrapper clientSceneWrapper;
@ -442,8 +444,6 @@ public class Globals {
//script engine
scriptEngine = new ScriptEngine();
scriptEngine.init();
//hitbox manager
clientHitboxManager = new HitboxManager();
//ai manager
aiManager = new AIManager();
//realm & data cell manager
@ -520,6 +520,7 @@ public class Globals {
//init fluid shader program
FluidChunkModelGeneration.fluidChunkShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/fluid2/fluid2.vs", "/Shaders/fluid2/fluid2.fs");
//init models
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere.glb");
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere_1.fbx");
assetManager.addModelPathToQueue("Models/basic/geometry/unitsphere_grey.fbx");

View File

@ -63,8 +63,8 @@ public class Main {
//initialize logging interfaces
LoggerInterface.initLoggers();
//gets pid of engine
System.out.println(ManagementFactory.getRuntimeMXBean().getName());
//gets java pid of engine
Globals.javaPID = ManagementFactory.getRuntimeMXBean().getName();
//load user settings
UserSettings.loadUserSettings();
@ -221,6 +221,8 @@ public class Main {
//main loop
while (running) {
try {
Globals.profiler.beginRootCpuSample("frame");
LoggerInterface.loggerEngine.DEBUG("Begin Main Loop Frame");
@ -396,6 +398,10 @@ public class Main {
LoggerInterface.loggerEngine.DEBUG("End Main Loop Frame");
Globals.profiler.endCpuSample();
} catch (NullPointerException ex){
LoggerInterface.loggerEngine.ERROR("Main frame uncaught NPE", ex);
}
}
LoggerInterface.loggerEngine.WARNING("ENGINE SHUTDOWN");

View File

@ -239,13 +239,21 @@ public class AssetManager {
//
//Pose Models
//
/**
* Adds a pose model to the list of pose models to load
* @param path The path to load
*/
public void addPoseModelPathToQueue(String path){
if(!poseModelsInQueue.contains(path) && !poseModelsLoadedIntoMemory.containsKey(path)){
poseModelsInQueue.add(path);
}
}
/**
* Fetches a pose model
* @param path The path to fetch
* @return The pose model if it exists, null otherwise
*/
public PoseModel fetchPoseModel(String path){
PoseModel rVal = null;
if(poseModelsLoadedIntoMemory.containsKey(path)){

View File

@ -36,6 +36,9 @@ public class Timekeeper {
//the maximum number of simulation frames that can happen in a row before the main loop immediately skips more
public static final int SIM_FRAME_HARDCAP = 3;
//step interval time size (for physics)
public static final float ENGINE_STEP_SIZE = 0.01f;
@ -135,4 +138,13 @@ public class Timekeeper {
return currentTime;
}
/**
* The number of frames we're simulating this cycle
* @return The number of frames we're simulating this cycle
*/
public long getDeltaFrames(){
//this should always return 1. We're always simulating 1 frame per run of the loop in main
return 1;
}
}

View File

@ -1,18 +1,16 @@
package electrosphere.entity;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import electrosphere.engine.Globals;
import electrosphere.renderer.actor.ActorUtils;
import electrosphere.renderer.actor.instance.InstancedActor;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
import electrosphere.server.poseactor.PoseActor;
import electrosphere.server.poseactor.PoseActorUtils;
public class EntityCreationUtils {
@ -82,7 +80,7 @@ public class EntityCreationUtils {
* @param modelPath The model path for the model to back the pose actor
*/
public static void makeEntityPoseable(Entity entity, String modelPath){
entity.putData(EntityDataStrings.POSE_ACTOR, new PoseActor(modelPath));
entity.putData(EntityDataStrings.POSE_ACTOR, PoseActorUtils.createPoseActorFromModelPath(modelPath));
entity.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
entity.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity());
entity.putData(EntityDataStrings.DATA_STRING_SCALE, new Vector3f(1,1,1));

View File

@ -282,6 +282,11 @@ public class EntityDataStrings {
* Pose actor
*/
public static final String POSE_ACTOR = "poseActor";
/**
* Server-specific btrees
*/
public static final String TREE_SERVERPLAYERVIEWDIR = "treeServerPlayerViewDir";
/*
Entity categories

View File

@ -1,32 +1,20 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package electrosphere.entity;
import electrosphere.engine.Globals;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree;
import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.actor.ActorUtils;
import electrosphere.renderer.model.Model;
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.poseactor.PoseActor;
import electrosphere.server.poseactor.PoseActorUtils;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
/**
*
* @author amaterasu
* Utilties for dealing with entities
*/
public class EntityUtils {
@ -90,7 +78,7 @@ public class EntityUtils {
*/
protected static Entity spawnPoseableEntity(String modelPath){
Entity rVal = new Entity();
rVal.putData(EntityDataStrings.POSE_ACTOR, new PoseActor(modelPath));
rVal.putData(EntityDataStrings.POSE_ACTOR, PoseActorUtils.createPoseActorFromModelPath(modelPath));
// rVal.putData(EntityDataStrings.DATA_STRING_MODEL_PATH, modelPath);
rVal.putData(EntityDataStrings.DATA_STRING_POSITION, new Vector3d(0,0,0));
rVal.putData(EntityDataStrings.DATA_STRING_ROTATION, new Quaterniond().identity());

View File

@ -3,19 +3,15 @@ package electrosphere.entity.state.attack;
import electrosphere.net.synchronization.BehaviorTreeIdEnums;
import electrosphere.collision.collidable.Collidable;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.client.firstPerson.FirstPersonTree;
import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree;
import electrosphere.entity.state.hitbox.HitboxState;
import electrosphere.entity.state.rotator.RotatorTree;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.collision.CollisionObjUtils;
@ -29,16 +25,11 @@ import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizableEnum;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.anim.Animation;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Quaternionfc;
import org.joml.Vector3d;
import org.joml.Vector3f;
@ -108,8 +99,8 @@ public class ClientAttackTree implements BehaviorTree {
String attackingPoint = null;
public ClientAttackTree(Entity e){
state = AttackTreeState.IDLE;
driftState = AttackTreeDriftState.NO_DRIFT;
setState(AttackTreeState.IDLE);
setDriftState(AttackTreeDriftState.NO_DRIFT);
parent = e;
}
@ -123,6 +114,9 @@ public class ClientAttackTree implements BehaviorTree {
return state;
}
/**
* Starts an attack
*/
public void start(){
currentMoveCanHold = false;
currentMoveHasWindup = false;
@ -135,8 +129,8 @@ public class ClientAttackTree implements BehaviorTree {
String attackType = getAttackType();
//if we can attack, setup doing so
if(canAttack(attackType)){
parent.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, attackType);
currentMoveset = (List<AttackMove>)parent.getData(attackType);
setAttackMoveTypeActive(attackType);
currentMoveset = getMoveset(attackType);
if(currentMoveset != null){
Globals.clientConnection.queueOutgoingMessage(EntityMessage.constructstartAttackMessage());
}
@ -148,23 +142,26 @@ public class ClientAttackTree implements BehaviorTree {
}
public void interrupt(){
state = AttackTreeState.IDLE;
setState(AttackTreeState.IDLE);
}
public void slowdown(){
state = AttackTreeState.COOLDOWN;
setState(AttackTreeState.COOLDOWN);
}
@Override
public void simulate(float deltaTime){
frameCurrent = frameCurrent + (float)Globals.timekeeper.getSimFrameTime();
frameCurrent = frameCurrent + (float)Globals.timekeeper.getDeltaFrames();
float velocity = CreatureUtils.getVelocity(parent);
Actor entityActor = EntityUtils.getActor(parent);
Vector3d position = EntityUtils.getPosition(parent);
Vector3d movementVector = CreatureUtils.getFacingVector(parent);
//synchronize move from server
if(this.currentMove == null && this.currentMoveId != null){
if(this.currentMoveset == null){
this.currentMoveset = getMoveset(getAttackType());
}
if(this.currentMove == null && this.currentMoveId != null && this.currentMoveset != null){
for(AttackMove move : currentMoveset){
if(move.getAttackMoveId().equals(currentMoveId)){
currentMove = move;
@ -183,23 +180,23 @@ public class ClientAttackTree implements BehaviorTree {
lastUpdateTime = updateTime;
switch(message.gettreeState()){
case 0:
state = AttackTreeState.WINDUP;
setState(AttackTreeState.WINDUP);
frameCurrent = 0;
// System.out.println("Set state STARTUP");
break;
case 1:
frameCurrent = currentMove.getWindupFrames()+1;
state = AttackTreeState.ATTACK;
setState(AttackTreeState.ATTACK);
// System.out.println("Set state MOVE");
break;
case 2:
frameCurrent = currentMove.getWindupFrames()+currentMove.getAttackFrames()+1;
state = AttackTreeState.COOLDOWN;
setState(AttackTreeState.COOLDOWN);
// System.out.println("Set state SLOWDOWN");
break;
case 3:
frameCurrent = 60;
state = AttackTreeState.IDLE;
setState(AttackTreeState.IDLE);
// System.out.println("Set state IDLE");
break;
}
@ -230,26 +227,22 @@ public class ClientAttackTree implements BehaviorTree {
//calculate the vector of movement
CollisionObjUtils.getCollidable(parent).addImpulse(new Impulse(new Vector3d(movementVector), new Vector3d(0,0,0), new Vector3d(0,0,0), currentMove.getDriftGoal() * Globals.timekeeper.getSimFrameTime(), "movement"));
if(frameCurrent > currentMove.getDriftFrameEnd()){
driftState = AttackTreeDriftState.NO_DRIFT;
setDriftState(AttackTreeDriftState.NO_DRIFT);
}
}
break;
case NO_DRIFT:
if(currentMove != null){
if(frameCurrent > currentMove.getDriftFrameStart() && frameCurrent < currentMove.getDriftFrameEnd()){
driftState = AttackTreeDriftState.DRIFT;
setDriftState(AttackTreeDriftState.DRIFT);
}
}
break;
}
// if(state != AttackTreeState.IDLE){
// System.out.println(frameCurrent);
// }
//state machine
switch(state){
case WINDUP:
case WINDUP: {
if(parent.containsKey(EntityDataStrings.CLIENT_ROTATOR_TREE)){
RotatorTree.getClientRotatorTree(parent).setActive(true);
}
@ -261,35 +254,31 @@ public class ClientAttackTree implements BehaviorTree {
}
FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonWindup().getName());
}
if(currentMoveCanHold && stillHold){
state = AttackTreeState.HOLD;
} else {
state = AttackTreeState.ATTACK;
}
} break;
case HOLD: {
if(entityActor != null){
if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(currentMove.getHoldAnimationName())){
entityActor.playAnimation(currentMove.getHoldAnimationName(),1);
entityActor.incrementAnimationTime(0.0001);
}
FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonHold().getName());
}
break;
case HOLD:
if(entityActor != null){
if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(animationName)){
entityActor.playAnimation(animationName,1);
entityActor.incrementAnimationTime(0.0001);
} break;
case ATTACK: {
if(entityActor != null && currentMove != null){
if(!entityActor.isPlayingAnimation() || !entityActor.isPlayingAnimation(currentMove.getAttackAnimationName())){
entityActor.playAnimation(currentMove.getAttackAnimationName(),1);
entityActor.incrementAnimationTime(0.0001);
}
FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonAttack().getName());
}
FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonHold().getName());
}
if(!stillHold){
state = AttackTreeState.ATTACK;
}
break;
case ATTACK:
if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached);
for(Entity hitbox : hitboxes){
HitboxUtils.getHitboxData(hitbox).setActive(true);
}
}
//activate hitboxes
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(HitboxState.hasHitboxState(currentAttached)){
HitboxState currentState = HitboxState.getHitboxState(currentAttached);
currentState.setActive(true);
}
}
if(firesProjectile && projectileToFire != null){
@ -325,34 +314,27 @@ public class ClientAttackTree implements BehaviorTree {
ProjectileUtils.clientSpawnBasicProjectile(projectileToFire, spawnPosition, arrowRotation, 750, initialVector, 0.03f);
projectileToFire = null;
}
if(currentMove != null && frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames()){
state = AttackTreeState.COOLDOWN;
}
break;
case COOLDOWN:
if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached);
for(Entity hitbox : hitboxes){
HitboxUtils.getHitboxData(hitbox).setActive(false);
}
}
} break;
case COOLDOWN: {
//deactive hitboxes
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(HitboxState.hasHitboxState(currentAttached)){
HitboxState currentState = HitboxState.getHitboxState(currentAttached);
currentState.setActive(false);
}
}
if(currentMove != null && frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames() + currentMove.getCooldownFrames()){
state = AttackTreeState.IDLE;
frameCurrent = 0;
if(parent.containsKey(EntityDataStrings.CLIENT_ROTATOR_TREE)){
RotatorTree.getClientRotatorTree(parent).setActive(false);
}
}
break;
case IDLE:
currentMove = null;
currentMoveset = null;
break;
} break;
case IDLE: {
currentMove = null;
currentMoveset = null;
} break;
}
}
@ -360,6 +342,10 @@ public class ClientAttackTree implements BehaviorTree {
networkMessageQueue.add(networkMessage);
}
/**
* Gets the current attack type
* @return The current attack type
*/
String getAttackType(){
String rVal = null;
if(ClientEquipState.hasEquipState(parent)){
@ -433,6 +419,23 @@ public class ClientAttackTree implements BehaviorTree {
}
return rVal;
}
/**
* Sets the current attack type of the entity
* @param attackType the current attack type
*/
public void setAttackMoveTypeActive(String attackType){
parent.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, attackType);
}
/**
* Gets the current moveset
* @param attackType the attack type
* @return The moveset if it exists
*/
public List<AttackMove> getMoveset(String attackType){
return (List<AttackMove>)parent.getData(attackType);
}
/**
* <p> Automatically generated </p>

View File

@ -9,22 +9,19 @@ import electrosphere.net.parser.net.message.SynchronizationMessage;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.attack.ClientAttackTree.AttackTreeDriftState;
import electrosphere.entity.state.attack.ClientAttackTree.AttackTreeState;
import electrosphere.entity.state.client.firstPerson.FirstPersonTree;
import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree;
import electrosphere.entity.state.hitbox.HitboxState;
import electrosphere.entity.state.movement.groundmove.ServerGroundMovementTree;
import electrosphere.entity.state.rotator.RotatorTree;
import electrosphere.entity.state.rotator.ServerRotatorTree;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.collision.CollisionObjUtils;
@ -37,17 +34,13 @@ import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.anim.Animation;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.poseactor.PoseActor;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Quaternionfc;
import org.joml.Vector3d;
import org.joml.Vector3f;
@ -58,9 +51,11 @@ import org.joml.Vector3f;
public class ServerAttackTree implements BehaviorTree {
@SyncedField
//the state of the attack tree
AttackTreeState state;
@SyncedField
//the state of drifting caused by the attack animation
AttackTreeDriftState driftState;
Entity parent;
@ -115,8 +110,8 @@ public class ServerAttackTree implements BehaviorTree {
String attackType = getAttackType();
//if we can attack, setup doing so
if(canAttack(attackType)){
parent.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, attackType);
currentMoveset = (List<AttackMove>)parent.getData(attackType);
setAttackMoveTypeActive(attackType);
currentMoveset = getMoveset(attackType);
if(currentMoveset != null){
if(currentMove == null){
currentMove = currentMoveset.get(0);
@ -171,7 +166,7 @@ public class ServerAttackTree implements BehaviorTree {
@Override
public void simulate(float deltaTime){
frameCurrent = frameCurrent + (float)Globals.timekeeper.getSimFrameTime();
frameCurrent = frameCurrent + (float)Globals.timekeeper.getDeltaFrames();
float velocity = CreatureUtils.getVelocity(parent);
PoseActor entityPoseActor = EntityUtils.getPoseActor(parent);
Vector3d position = EntityUtils.getPosition(parent);
@ -247,7 +242,7 @@ public class ServerAttackTree implements BehaviorTree {
//state machine
switch(state){
case WINDUP:
case WINDUP: {
if(parent.containsKey(EntityDataStrings.SERVER_ROTATOR_TREE)){
ServerRotatorTree.getServerRotatorTree(parent).setActive(true);
}
@ -278,28 +273,32 @@ public class ServerAttackTree implements BehaviorTree {
0
)
);
break;
case HOLD:
if(entityPoseActor != null){
if(!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationName)){
entityPoseActor.playAnimation(animationName,1);
entityPoseActor.incrementAnimationTime(0.0001);
} break;
case HOLD: {
if(entityPoseActor != null){
if(!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(animationName)){
entityPoseActor.playAnimation(animationName,1);
entityPoseActor.incrementAnimationTime(0.0001);
}
}
}
if(!stillHold){
setState(AttackTreeState.ATTACK);
}
break;
case ATTACK:
if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached);
for(Entity hitbox : hitboxes){
HitboxUtils.getHitboxData(hitbox).setActive(true);
}
}
if(!stillHold){
setState(AttackTreeState.ATTACK);
}
} break;
case ATTACK: {
if(entityPoseActor != null && currentMove != null){
if(!entityPoseActor.isPlayingAnimation() || !entityPoseActor.isPlayingAnimation(currentMove.getAttackAnimationName())){
entityPoseActor.playAnimation(currentMove.getAttackAnimationName(),1);
entityPoseActor.incrementAnimationTime(0.0001);
}
FirstPersonTree.conditionallyPlayAnimation(Globals.firstPersonEntity, currentMove.getAnimationFirstPersonAttack().getName());
}
//activate hitboxes
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(HitboxState.hasHitboxState(currentAttached)){
HitboxState currentState = HitboxState.getHitboxState(currentAttached);
currentState.setActive(true);
}
}
if(firesProjectile && projectileToFire != null){
@ -353,17 +352,14 @@ public class ServerAttackTree implements BehaviorTree {
1
)
);
break;
case COOLDOWN:
if(parent.containsKey(EntityDataStrings.ATTACH_CHILDREN_LIST)){
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(currentAttached.containsKey(EntityDataStrings.HITBOX_ASSOCIATED_LIST)){
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(currentAttached);
for(Entity hitbox : hitboxes){
HitboxUtils.getHitboxData(hitbox).setActive(false);
}
}
} break;
case COOLDOWN: {
//deactive hitboxes
List<Entity> attachedEntities = AttachUtils.getChildrenList(parent);
for(Entity currentAttached : attachedEntities){
if(HitboxState.hasHitboxState(currentAttached)){
HitboxState currentState = HitboxState.getHitboxState(currentAttached);
currentState.setActive(false);
}
}
if(frameCurrent > currentMove.getWindupFrames() + currentMove.getAttackFrames() + currentMove.getCooldownFrames()){
@ -387,11 +383,11 @@ public class ServerAttackTree implements BehaviorTree {
2
)
);
break;
case IDLE:
currentMove = null;
currentMoveset = null;
break;
} break;
case IDLE: {
currentMove = null;
currentMoveset = null;
} break;
}
}
@ -471,6 +467,23 @@ public class ServerAttackTree implements BehaviorTree {
}
return rVal;
}
/**
* Sets the current attack type of the entity
* @param attackType the current attack type
*/
public void setAttackMoveTypeActive(String attackType){
parent.putData(EntityDataStrings.ATTACK_MOVE_TYPE_ACTIVE, attackType);
}
/**
* Gets the current moveset
* @param attackType the attack type
* @return The moveset if it exists
*/
public List<AttackMove> getMoveset(String attackType){
return (List<AttackMove>)parent.getData(attackType);
}
/**
* <p> Automatically generated </p>

View File

@ -115,7 +115,7 @@ public class FirstPersonTree implements BehaviorTree {
* @param animationName the name of the animation
*/
public static void conditionallyPlayAnimation(Entity entity, String animationName){
if(hasTree(entity)){
if(entity != null && hasTree(entity)){
getTree(entity).playAnimation(animationName);
}
}

View File

@ -72,7 +72,6 @@ public class ClientEquipState implements BehaviorTree {
boolean hasEquipped = hasEquippedAtPoint(point.getEquipPointId());
boolean targetIsItem = ItemUtils.isItem(toEquip);
boolean targetIsAttached = AttachUtils.isAttached(toEquip);
boolean targetHasWhitelist = ItemUtils.hasEquipList(toEquip);
String equipItemClass = ItemUtils.getEquipClass(toEquip);
List<String> pointEquipClassList = point.getEquipClassWhitelist();
boolean itemIsInPointWhitelist = pointEquipClassList.contains(equipItemClass);
@ -90,7 +89,7 @@ public class ClientEquipState implements BehaviorTree {
* @param toEquip The entity to equip
* @param point The equipment point to equip to
*/
public void clientAttemptEquip(Entity toEquip, EquipPoint point){
public void attemptEquip(Entity toEquip, EquipPoint point){
boolean hasEquipped = hasEquippedAtPoint(point.getEquipPointId());
boolean targetIsItem = ItemUtils.isItem(toEquip);
boolean targetIsAttached = AttachUtils.isAttached(toEquip);

View File

@ -0,0 +1,370 @@
package electrosphere.entity.state.hitbox;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.joml.Quaterniond;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DGeom;
import electrosphere.collision.CollisionBodyCreation;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.collision.hitbox.HitboxManager;
import electrosphere.collision.hitbox.HitboxUtils.HitboxPositionCallback;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.game.data.collidable.HitboxData;
/**
* The hitbox state of this entity
*/
public class HitboxState {
/**
* Types of hitboxes
*/
public enum HitboxType {
HIT, // damages another entity
HURT, // receives damage from another entity
BLOCK, // blocks a hit from another entity
}
//the parent entity of the hitbox state
Entity parent;
//the body that contains all the hitbox shapes
DBody body;
//The collidable associated with the body
Collidable collidable;
//the map of bone -> hitbox shape in ode4j
Map<String,DGeom> hitboxGeomMap = new HashMap<String,DGeom>();
//the map of geometry -> hitbox shape status, useful for finding data about a given hitbox during collision
Map<DGeom,HitboxShapeStatus> geomBoneMap = new HashMap<DGeom,HitboxShapeStatus>();
//callback to provide a position for the hitbox each frame
HitboxPositionCallback positionCallback;
//controls whether the hitbox state is active or not
boolean active = true;
//the associated manager
HitboxManager manager;
/**
* Create hitbox state for an entity
* @param collisionEngine the collision engine
* @param entity The entity to attach the state to
* @param hitboxListRaw The list of hitbox data to apply
* @return The hitbox state that has been attached to the entity
*/
public static HitboxState attachHitboxState(HitboxManager manager, Entity entity, List<HitboxData> hitboxListRaw){
HitboxState rVal = new HitboxState();
//create the shapes
for(HitboxData hitboxDataRaw : hitboxListRaw){
DGeom geom = CollisionBodyCreation.createShapeSphere(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), Collidable.TYPE_OBJECT_BIT);
rVal.hitboxGeomMap.put(hitboxDataRaw.getBone(),geom);
HitboxType type = HitboxType.HIT;
switch(hitboxDataRaw.getType()){
case "HIT": {
type = HitboxType.HIT;
} break;
case "HURT": {
type = HitboxType.HURT;
} break;
}
rVal.geomBoneMap.put(geom,new HitboxShapeStatus(hitboxDataRaw.getBone(), type, true));
}
//create body with all the shapes
DGeom[] geomArray = rVal.hitboxGeomMap.values().toArray(new DGeom[rVal.hitboxGeomMap.values().size()]);
rVal.body = CollisionBodyCreation.createBodyWithShapes(manager.getCollisionEngine(), geomArray);
//register collidable with collision engine
Collidable collidable = new Collidable(entity, Collidable.TYPE_OBJECT);
manager.getCollisionEngine().registerCollisionObject(rVal.body, collidable);
//attach
entity.putData(EntityDataStrings.HITBOX_DATA, rVal);
rVal.parent = entity;
//register
manager.registerHitbox(rVal);
rVal.manager = manager;
return rVal;
}
/**
* Create hitbox state for an entity
* @param collisionEngine the collision engine
* @param entity The entity to attach the state to
* @param data The hitbox data to apply
* @param callback The callback that provides a position for the hitbox each frame
* @return The hitbox state that has been attached to the entity
*/
public static HitboxState attachHitboxStateWithCallback(HitboxManager manager, CollisionEngine collisionEngine, Entity entity, HitboxData data, HitboxPositionCallback callback){
HitboxState rVal = new HitboxState();
//create the shapes
rVal.hitboxGeomMap.put(data.getBone(),CollisionBodyCreation.createShapeSphere(collisionEngine, data.getRadius(), Collidable.TYPE_OBJECT_BIT));
//create body with all the shapes
DGeom[] geomArray = rVal.hitboxGeomMap.values().toArray(new DGeom[rVal.hitboxGeomMap.values().size()]);
rVal.body = CollisionBodyCreation.createBodyWithShapes(collisionEngine, geomArray);
//register collidable with collision engine
Collidable collidable = new Collidable(entity, Collidable.TYPE_OBJECT);
collisionEngine.registerCollisionObject(rVal.body, collidable);
//attach
entity.putData(EntityDataStrings.HITBOX_DATA, rVal);
rVal.parent = entity;
//register
manager.registerHitbox(rVal);
rVal.manager = manager;
return rVal;
}
/**
* Updates the positions of all hitboxes
*/
public void updateHitboxPositions(CollisionEngine collisionEngine){
if(parent != null && EntityUtils.getActor(parent) != null){
if(!this.hitboxGeomMap.isEmpty()){
Vector3d entityPosition = EntityUtils.getPosition(parent);
this.body.setPosition(PhysicsUtils.jomlVecToOdeVec(entityPosition));
for(String boneName : this.hitboxGeomMap.keySet()){
DGeom geom = this.hitboxGeomMap.get(boneName);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3f bonePosition = EntityUtils.getActor(parent).getBonePosition(boneName);
Vector3d parentPos = EntityUtils.getPosition(parent);
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
Quaterniond rotation = new Quaterniond(parentRotation);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, worldPosition, rotation);
}
} else if(positionCallback != null){
DGeom geom = body.getGeomIterator().next();
Vector3d worldPosition = this.positionCallback.getPosition();
Quaterniond rotation = new Quaterniond().identity();
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, worldPosition, rotation);
}
} else if(parent != null && EntityUtils.getPoseActor(parent) != null){
if(!this.hitboxGeomMap.isEmpty()){
Vector3d entityPosition = EntityUtils.getPosition(parent);
this.body.setPosition(PhysicsUtils.jomlVecToOdeVec(entityPosition));
for(String boneName : this.hitboxGeomMap.keySet()){
DGeom geom = this.hitboxGeomMap.get(boneName);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f positionScale = EntityUtils.getScale(parent);
Vector3d worldPosition = new Vector3d();
Vector3f bonePosition = EntityUtils.getPoseActor(parent).getBonePosition(boneName);
Vector3d parentPos = EntityUtils.getPosition(parent);
worldPosition.set(bonePosition.x,bonePosition.y,bonePosition.z);
Quaterniond rotation = new Quaterniond(parentRotation);
worldPosition = worldPosition.mul(positionScale);
worldPosition = worldPosition.rotate(rotation);
worldPosition.add(new Vector3f((float)parentPos.x,(float)parentPos.y,(float)parentPos.z));
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, worldPosition, rotation);
}
} else if(positionCallback != null){
DGeom geom = body.getGeomIterator().next();
Vector3d worldPosition = this.positionCallback.getPosition();
Quaterniond rotation = new Quaterniond().identity();
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, worldPosition, rotation);
}
}
}
/**
* Gets the status of a shape in the hitbox object
* @param geom The geometry that is the shape within the hitbox data
* @return The status of the shape
*/
public HitboxShapeStatus getShapeStatus(DGeom geom){
return this.geomBoneMap.get(geom);
}
/**
* Gets the hitbox state of the entity
* @param entity the entity
* @return the hitbox state if it exists
*/
public static HitboxState getHitboxState(Entity entity){
return (HitboxState)entity.getData(EntityDataStrings.HITBOX_DATA);
}
/**
* Checks whether the entity has hitbox state or not
* @param entity the entity to check
* @return true if there is hitbox state, false otherwise
*/
public static boolean hasHitboxState(Entity entity){
return entity.containsKey(EntityDataStrings.HITBOX_DATA);
}
/**
* Destroys the hitbox state and removes it from the entity
* @param entity the entity
* @return The hitbox state if it exists, null otherwise
*/
public static HitboxState destroyHitboxState(Entity entity){
HitboxState state = null;
if(hasHitboxState(entity)){
state = getHitboxState(entity);
state.manager.deregisterHitbox(state);
}
return state;
}
/**
* Gets whether the hitbox state is active or not
* @return true if active, false otherwise
*/
public boolean isActive(){
return active;
}
/**
* Sets the active state of the hitbox
* @param state true to make it active, false otherwise
*/
public void setActive(boolean state){
this.active = state;
}
/**
* Gets the collection of all DGeoms in the data
* @return the collection of all DGeoms
*/
public Collection<DGeom> getGeometries(){
return this.hitboxGeomMap.values();
}
/**
* Gets the set of bone names in the state data
* @return The set of bone names in the state data
*/
public Set<String> getBones(){
return this.hitboxGeomMap.keySet();
}
/**
* Gets geometry on a single hitbox based on its bone name
* @param boneName the bone name
* @return the hitbox geometry
*/
public DGeom getGeometry(String boneName){
return this.hitboxGeomMap.get(boneName);
}
/**
* The status of a single shape inside the overall hitbox data
* IE a single sphere on the overall body
*/
public static class HitboxShapeStatus {
//the name of the bone the hitbox is attached to
String boneName;
//the type of hitbox
HitboxType type;
//controls whether the hitbox is active
boolean isActive;
/**
* Creates a status object for a hitbox
* @param boneName The name of the bone the hitbox is attached to, if any
* @param type The type of hitbox
* @param isActive if the hitbox is active or not
*/
public HitboxShapeStatus(String boneName, HitboxType type, boolean isActive){
this.boneName = boneName;
this.type = type;
this.isActive = isActive;
}
/**
* Gets the name of the bone the hitbox is attached to
* @return The name of the bone
*/
public String getBoneName(){
return boneName;
}
/**
* Sets the name of the bone the hitbox is attached to
* @param boneName The bone name
*/
public void setBoneName(String boneName){
this.boneName = boneName;
}
/**
* Gets the type of hitbox
* @return The type
*/
public HitboxType getType(){
return type;
}
/**
* Sets the type of hitbox
* @param type The type
*/
public void setType(HitboxType type){
this.type = type;
}
/**
* Gets whether the hitbox is active or not
* @return true if active, false otherwise
*/
public boolean isActive(){
return isActive;
}
/**
* Sets whether the hitbox is active or not
* @param active true for active, false otherwise
*/
public void setActive(boolean active){
this.isActive = active;
}
}
}

View File

@ -3,20 +3,13 @@ package electrosphere.entity.state.movement.groundmove;
import electrosphere.net.synchronization.BehaviorTreeIdEnums;
import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.GravityUtils;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.game.data.creature.type.movement.GroundMovementSystem;
import electrosphere.entity.ClientEntityUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
@ -28,24 +21,17 @@ import electrosphere.entity.state.movement.FallTree;
import electrosphere.entity.state.movement.JumpTree;
import electrosphere.entity.state.movement.SprintTree;
import electrosphere.entity.state.movement.SprintTree.SprintTreeState;
import electrosphere.net.NetUtils;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizableEnum;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
import electrosphere.renderer.anim.Animation;
import electrosphere.renderer.model.Model;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.renderer.actor.Actor;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.math.DVector3;
import org.ode4j.math.DVector3C;
import org.ode4j.ode.DBody;
@ -69,6 +55,7 @@ public class ClientGroundMovementTree implements BehaviorTree {
* The relative facing of the character to its rotation
* (ie is it strafing, moveing straight forward, backpedaling, etc)
*/
@SynchronizableEnum
public static enum MovementRelativeFacing {
FORWARD,
LEFT,
@ -126,7 +113,6 @@ public class ClientGroundMovementTree implements BehaviorTree {
//if we aren't the server, alert the server we intend to walk forward
Vector3d position = EntityUtils.getPosition(parent);
Quaterniond rotation = EntityUtils.getRotation(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
float velocity = CreatureUtils.getVelocity(parent);
Globals.clientConnection.queueOutgoingMessage(
EntityMessage.constructmoveUpdateMessage(
@ -156,7 +142,6 @@ public class ClientGroundMovementTree implements BehaviorTree {
//if we aren't the server, alert the server we intend to slow down
Vector3d position = EntityUtils.getPosition(parent);
Quaterniond rotation = EntityUtils.getRotation(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
float velocity = CreatureUtils.getVelocity(parent);
Globals.clientConnection.queueOutgoingMessage(
EntityMessage.constructmoveUpdateMessage(

View File

@ -3,15 +3,10 @@ package electrosphere.entity.state.movement.groundmove;
import electrosphere.net.synchronization.BehaviorTreeIdEnums;
import electrosphere.entity.state.collidable.Impulse;
import electrosphere.entity.state.gravity.GravityUtils;
import electrosphere.collision.CollisionEngine;
import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
@ -25,28 +20,21 @@ import electrosphere.entity.state.movement.ServerSprintTree;
import electrosphere.entity.state.movement.ServerSprintTree.SprintTreeState;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementRelativeFacing;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree.MovementTreeState;
import electrosphere.net.NetUtils;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.synchronization.annotation.SyncedField;
import electrosphere.net.synchronization.annotation.SynchronizedBehaviorTree;
import electrosphere.renderer.anim.Animation;
import electrosphere.renderer.model.Model;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
import electrosphere.server.poseactor.PoseActor;
import electrosphere.renderer.actor.Actor;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.ode4j.math.DVector3C;
import org.ode4j.ode.DBody;
@SynchronizedBehaviorTree(name = "serverGroundMovementTree", isServer = false, correspondingTree="clientGroundMovementTree")
@SynchronizedBehaviorTree(name = "serverGroundMovementTree", isServer = true, correspondingTree="clientGroundMovementTree")
/*
Behavior tree for movement in an entity
*/
@ -91,6 +79,10 @@ public class ServerGroundMovementTree implements BehaviorTree {
return state;
}
/**
* Starts the server movement tree
* @param facing The facing dir to start with
*/
public void start(MovementRelativeFacing facing){
if(canStartMoving()){
setFacing(facing);
@ -98,7 +90,6 @@ public class ServerGroundMovementTree implements BehaviorTree {
//if we aren't the server, alert the server we intend to walk forward
Vector3d position = EntityUtils.getPosition(parent);
Quaterniond rotation = EntityUtils.getRotation(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
float velocity = CreatureUtils.getVelocity(parent);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
EntityMessage.constructmoveUpdateMessage(
@ -128,7 +119,6 @@ public class ServerGroundMovementTree implements BehaviorTree {
//if we aren't the server, alert the server we intend to slow down
Vector3d position = EntityUtils.getPosition(parent);
Quaterniond rotation = EntityUtils.getRotation(parent);
Vector3d facingVector = CreatureUtils.getFacingVector(parent);
float velocity = CreatureUtils.getVelocity(parent);
DataCellSearchUtils.getEntityDataCell(parent).broadcastNetworkMessage(
EntityMessage.constructmoveUpdateMessage(
@ -213,9 +203,20 @@ public class ServerGroundMovementTree implements BehaviorTree {
case MOVEUPDATE: {
if(updateTime >= lastUpdateTime){
lastUpdateTime = updateTime;
switch(message.gettreeState()){
//0 is startup
case 0: {
start(MovementRelativeFacing.FORWARD);
} break;
case 2: {
slowdown();
} break;
default: {
} break;
}
//we want to always update the server facing vector with where the client says they're facing
EntityUtils.getRotation(parent).set(message.getrotationX(),message.getrotationY(),message.getrotationZ(),message.getrotationW());
CreatureUtils.setFacingVector(parent, new Vector3d(0,0,1).rotate(EntityUtils.getRotation(parent)));
break;
}
} break;

View File

@ -0,0 +1,85 @@
package electrosphere.entity.state.server;
import org.joml.Vector3d;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.types.creature.CreatureUtils;
/**
* Stores the direction that the server thinks the player is looking
*/
public class ServerPlayerViewDirTree implements BehaviorTree {
//the direction of the view
Vector3d playerViewDir = new Vector3d();
//the last time this value was updated
long lastUpdateTime = 0;
//the parent entity
Entity parent;
@Override
public void simulate(float deltaTime) {
}
/**
* Constructor
* @param parent
*/
private ServerPlayerViewDirTree(Entity parent){
this.parent = parent;
}
/**
* Attaches a ServerPlayerViewDirTree to a given entity
* @param entity The entity to add to
*/
public static void attachServerPlayerViewDirTree(Entity entity){
ServerPlayerViewDirTree tree = new ServerPlayerViewDirTree(entity);
entity.putData(EntityDataStrings.TREE_SERVERPLAYERVIEWDIR, tree);
}
/**
* Gets the server player view dir tree if it exists
* @param entity The entity to get from
* @return The ServerPlayerViewDirTree if it exists, null otherwise
*/
public static ServerPlayerViewDirTree getTree(Entity entity){
return (ServerPlayerViewDirTree)entity.getData(EntityDataStrings.TREE_SERVERPLAYERVIEWDIR);
}
/**
* Checks whether the entity has a copy of this btree or not
* @param entity The entity
* @return true if the entity has the btree, false otherwise
*/
public static boolean hasTree(Entity entity){
return entity.containsKey(EntityDataStrings.TREE_SERVERPLAYERVIEWDIR);
}
/**
* Gets the player view dir
* @return The player view dir
*/
public Vector3d getPlayerViewDir(){
return playerViewDir;
}
/**
* Sets the player view dir vector
* @param playerViewDir The player view dir vector
*/
public void setPlayerViewDir(Vector3d playerViewDir, long time){
if(time > lastUpdateTime){
this.playerViewDir = playerViewDir;
this.lastUpdateTime = time;
CreatureUtils.setFacingVector(parent, new Vector3d(-playerViewDir.x,0,-playerViewDir.z));
}
}
}

View File

@ -7,7 +7,6 @@ import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.renderer.actor.Actor;
import electrosphere.renderer.model.Model;
import electrosphere.server.datacell.ServerDataCell;
import electrosphere.server.datacell.utils.ServerEntityTagUtils;
import electrosphere.server.poseactor.PoseActor;
@ -18,10 +17,8 @@ import java.util.List;
import org.joml.Matrix4d;
import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector4d;
/**
* Utilities for attaching entities to entities
@ -39,7 +36,28 @@ public class AttachUtils {
// FUNCTIONS TO UPDATE ATTACHMENTS FOR CURRENT FRAME
//
///
///
/// SERVER
///
///
/**
* Updates positions of all attached entities in a data cell
* @param cell The data cell
*/
public static void serverUpdateAttachedEntityPositions(ServerDataCell cell){
Globals.profiler.beginCpuSample("AttachUtils.serverUpdateAttachedEntityPositions");
serverUpdateBoneAttachedEntityPositions(cell);
serverUpdateNonBoneAttachments(cell);
Globals.profiler.endCpuSample();
}
/**
* Updates entities attached to bones of actors in a data cell
* @param cell The data cell
*/
public static void serverUpdateBoneAttachedEntityPositions(ServerDataCell cell){
for(Entity currentEntity : cell.getScene().getEntitiesWithTag(EntityTags.BONE_ATTACHED)){
Entity parent;
if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){
@ -68,25 +86,97 @@ public class AttachUtils {
.mul(offsetRotation)
.normalize();
}
} else if(currentEntity.getData(EntityDataStrings.ATTACH_TARGET_BASE)!=null){
Vector3d positionOffset = getAttachPositionOffset(currentEntity);
Vector3d parentPosition = EntityUtils.getPosition(parent);
EntityUtils.getPosition(currentEntity).set(new Vector3d(parentPosition).add(positionOffset));
}
}
}
/**
* Updates entities that aren't attached to a bone directly in a data cell
* @param cell the data cell
*/
private static void serverUpdateNonBoneAttachments(ServerDataCell cell){
Globals.profiler.beginCpuSample("AttachUtils.serverUpdateNonBoneAttachments");
Matrix4d parentTransform = new Matrix4d().identity();
Vector3d position = new Vector3d();
Quaterniond rotation = new Quaterniond();
Vector3d scaleRaw = new Vector3d();
Vector3f scale = new Vector3f();
Entity parent;
Matrix4f transform;
//update entities attached to centerpoint + transform of other entities
for(Entity currentEntity : cell.getScene().getEntitiesWithTag(EntityTags.TRANSFORM_ATTACHED)){
if((parent = (Entity)currentEntity.getData(EntityDataStrings.ATTACH_PARENT))!=null){
if((transform = getTransformOffset(currentEntity))!=null){
//parent objects
Vector3d parentPosition = EntityUtils.getPosition(parent);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3f parentScale = EntityUtils.getScale(parent);
// calculate new transform for current entity
parentTransform.identity()
.translate(parentPosition)
.rotate(parentRotation)
.scale(parentScale.x,parentScale.y,parentScale.z)
.mul(transform);
//transform bone space
parentTransform.getTranslation(position);
parentTransform.getUnnormalizedRotation(rotation).normalize();
parentTransform.getScale(scaleRaw);
scale.set((float)scaleRaw.x,(float)scaleRaw.y,(float)scaleRaw.z);
//transform worldspace
// position.add(new Vector3d(EntityUtils.getPosition(parent)));
//set
EntityUtils.getPosition(currentEntity).set(position);
EntityUtils.getRotation(currentEntity).set(rotation);
EntityUtils.getScale(currentEntity).set(scale);
}
}
}
Globals.profiler.endCpuSample();
}
///
///
/// CLIENT
///
///
/**
* Client version of attachment update functions
*/
public static void clientUpdateAttachedEntityPositions(){
Globals.profiler.beginCpuSample("AttachUtils.clientUpdateAttachedEntityPositions");
updateBoneAttachments();
updateNonBoneAttachments();
clientUpdateBoneAttachments();
clientUpdateNonBoneAttachments();
Globals.profiler.endCpuSample();
}
/**
* Updates entities attached to bones
*/
private static void updateBoneAttachments(){
Globals.profiler.beginCpuSample("AttachUtils.updateBoneAttachments");
private static void clientUpdateBoneAttachments(){
Globals.profiler.beginCpuSample("AttachUtils.clientUpdateBoneAttachments");
//update entities attached to bones of other entities
for(Entity currentEntity : Globals.clientSceneWrapper.getScene().getEntitiesWithTag(EntityTags.BONE_ATTACHED)){
Entity parent;
@ -128,7 +218,10 @@ public class AttachUtils {
Globals.profiler.endCpuSample();
}
private static void updateNonBoneAttachments(){
/**
* Updates entities that aren't attached to a bone directly
*/
private static void clientUpdateNonBoneAttachments(){
Globals.profiler.beginCpuSample("AttachUtils.updateNonBoneAttachments");
Matrix4d parentTransform = new Matrix4d().identity();
Vector3d position = new Vector3d();
@ -334,6 +427,11 @@ public class AttachUtils {
// FUNCTIONS TO DETATCH AN ENTITY
//
/**
* Detatches an entity on the server
* @param parent The parent entity
* @param toAttach The attached entity
*/
public static void serverDetatchEntityFromEntityAtBone(Entity parent, Entity toAttach){
ServerEntityTagUtils.removeTagFromEntity(toAttach, EntityTags.BONE_ATTACHED);
toAttach.removeData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED);
@ -344,6 +442,11 @@ public class AttachUtils {
}
}
/**
* Detatches an entity on the client
* @param parent The parent entity
* @param toAttach The attached entity
*/
public static void clientDetatchEntityFromEntityAtBone(Entity parent, Entity toAttach){
Globals.clientSceneWrapper.getScene().removeEntityFromTag(toAttach, EntityTags.BONE_ATTACHED);
toAttach.removeData(EntityDataStrings.ATTACH_ENTITY_IS_ATTACHED);

View File

@ -30,6 +30,7 @@ import electrosphere.entity.state.equip.ClientEquipState;
import electrosphere.entity.state.equip.ServerEquipState;
import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.hitbox.HitboxState;
import electrosphere.entity.state.idle.IdleTree;
import electrosphere.entity.state.idle.ServerIdleTree;
import electrosphere.entity.state.inventory.ClientInventoryState;
@ -103,26 +104,26 @@ public class CreatureUtils {
Actor creatureActor = EntityUtils.getActor(rVal);
EntityUtils.setEntityType(rVal, ENTITY_TYPE_CREATURE);
EntityUtils.setEntitySubtype(rVal, type);
for(HitboxData hitboxdata : rawType.getHitboxes()){
List<Entity> hitboxList = new LinkedList<Entity>();
List<Entity> hurtboxList = new LinkedList<Entity>();
if(hitboxdata.getType().equals("hit")){
Entity hitbox = HitboxUtils.clientSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius());
Globals.clientHitboxManager.registerHitbox(hitbox);
hitboxList.add(hitbox);
} else if(hitboxdata.getType().equals("hurt")){
Entity hurtbox = HitboxUtils.clientSpawnRegularHurtbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius());
Globals.clientHitboxManager.registerHitbox(hurtbox);
hurtboxList.add(hurtbox);
}
rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST, hitboxList);
rVal.putData(EntityDataStrings.HURTBOX_ASSOCIATED_LIST, hurtboxList);
}
//Physics object
///
///
/// HITBOX DATA
///
///
HitboxState.attachHitboxState(Globals.clientSceneWrapper.getHitboxManager(), rVal, rawType.getHitboxes());
//
//
// PHYSICS
//
//
if(rawType.getCollidable() != null){
CollidableTemplate physicsTemplate = rawType.getCollidable();
PhysicsEntityUtils.clientAttachCollidableTemplate(rVal, physicsTemplate);
}
//
//
// MOVEMENT SYSTEMS
@ -390,21 +391,17 @@ public class CreatureUtils {
EntityCreationUtils.makeEntityPoseable(rVal, rawType.getModelPath());
PoseActor creatureActor = EntityUtils.getPoseActor(rVal);
for(HitboxData hitboxdata : rawType.getHitboxes()){
List<Entity> hitboxList = new LinkedList<Entity>();
List<Entity> hurtboxList = new LinkedList<Entity>();
if(hitboxdata.getType().equals("hit")){
Entity hitbox = HitboxUtils.serverSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius());
realm.getHitboxManager().registerHitbox(hitbox);
hitboxList.add(hitbox);
} else if(hitboxdata.getType().equals("hurt")){
Entity hurtbox = HitboxUtils.serverSpawnRegularHurtbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius());
realm.getHitboxManager().registerHitbox(hurtbox);
hurtboxList.add(hurtbox);
}
rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST, hitboxList);
rVal.putData(EntityDataStrings.HURTBOX_ASSOCIATED_LIST, hurtboxList);
}
//
//
// Hitbox stuff
//
//
HitboxState.attachHitboxState(realm.getHitboxManager(), rVal, rawType.getHitboxes());
//
//
// Physics stuff
//
//
if(rawType.getCollidable() != null){
CollidableTemplate physicsTemplate = rawType.getCollidable();
PhysicsEntityUtils.serverAttachCollidableTemplate(realm, rVal, physicsTemplate);

View File

@ -26,6 +26,7 @@ import electrosphere.entity.state.collidable.ClientCollidableTree;
import electrosphere.entity.state.collidable.ServerCollidableTree;
import electrosphere.entity.state.gravity.ClientGravityTree;
import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.hitbox.HitboxState;
import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.game.data.item.type.EquipWhitelist;
@ -59,13 +60,7 @@ public class ItemUtils {
rVal.putData(EntityDataStrings.ITEM_IS_WEAPON, true);
WeaponData weaponData = item.getWeaponData();
if(weaponData.getHitboxes() != null){
List<Entity> hitboxList = new LinkedList<Entity>();
for(HitboxData hitboxdata : weaponData.getHitboxes()){
Entity hitbox = HitboxUtils.clientSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius());
Globals.clientHitboxManager.registerHitbox(hitbox);
hitboxList.add(hitbox);
}
rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST,hitboxList);
HitboxState.attachHitboxState(Globals.clientSceneWrapper.getHitboxManager(), rVal, weaponData.getHitboxes());
}
rVal.putData(EntityDataStrings.ITEM_WEAPON_CLASS,weaponData.getWeaponClass());
rVal.putData(EntityDataStrings.ITEM_WEAPON_DATA_RAW,weaponData);
@ -138,13 +133,7 @@ public class ItemUtils {
rVal.putData(EntityDataStrings.ITEM_IS_WEAPON, true);
WeaponData weaponData = item.getWeaponData();
if(weaponData.getHitboxes() != null){
List<Entity> hitboxList = new LinkedList<Entity>();
for(HitboxData hitboxdata : weaponData.getHitboxes()){
Entity hitbox = HitboxUtils.serverSpawnRegularHitbox(rVal, hitboxdata.getBone(), hitboxdata.getRadius());
realm.getHitboxManager().registerHitbox(hitbox);
hitboxList.add(hitbox);
}
rVal.putData(EntityDataStrings.HITBOX_ASSOCIATED_LIST,hitboxList);
HitboxState.attachHitboxState(realm.getHitboxManager(), rVal, weaponData.getHitboxes());
}
rVal.putData(EntityDataStrings.ITEM_WEAPON_CLASS,weaponData.getWeaponClass());
rVal.putData(EntityDataStrings.ITEM_WEAPON_DATA_RAW,weaponData);
@ -378,13 +367,7 @@ public class ItemUtils {
//this deregisters from all four & unhooks rigid bodies from the physics runtime
Globals.clientSceneWrapper.getCollisionEngine().destroyEntityThatHasPhysics(item);
//destroy hitboxes
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(item);
if(hitboxes != null){
for(Entity hitbox : hitboxes){
Globals.clientHitboxManager.deregisterHitbox(hitbox);
HitboxUtils.getHitboxData(hitbox).setActive(false);
}
}
HitboxState.destroyHitboxState(item);
//destroy graphics
EntityUtils.cleanUpEntity(item);
}
@ -401,13 +384,7 @@ public class ItemUtils {
if(itemRealm != null){
itemRealm.getCollisionEngine().destroyEntityThatHasPhysics(item);
//destroy hitboxes
List<Entity> hitboxes = HitboxUtils.getHitboxAssociatedList(item);
if(hitboxes != null){
for(Entity hitbox : hitboxes){
itemRealm.getHitboxManager().deregisterHitbox(hitbox);
HitboxUtils.getHitboxData(hitbox).setActive(false);
}
}
HitboxState.destroyHitboxState(item);
}
//destroy graphics
EntityUtils.cleanUpEntity(item);

View File

@ -16,7 +16,9 @@ import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.state.hitbox.HitboxState;
import electrosphere.entity.state.movement.ProjectileTree;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.game.data.projectile.ProjectileType;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.ServerBehaviorTreeUtils;
@ -92,11 +94,15 @@ public class ProjectileUtils {
List<Entity> filter = new LinkedList<Entity>();
filter.add(parent);
//collidable
HitboxUtils.clientSpawnRegularHitbox(rVal, new HitboxPositionCallback() {
public Vector3d getPosition(){
return EntityUtils.getPosition(rVal);
HitboxData hitboxData = new HitboxData();
hitboxData.setRadius(rawType.getHitboxRadius());
HitboxState.attachHitboxStateWithCallback(Globals.clientSceneWrapper.getHitboxManager(), Globals.clientSceneWrapper.getCollisionEngine(), rVal, hitboxData,
new HitboxPositionCallback() {
public Vector3d getPosition(){
return EntityUtils.getPosition(rVal);
}
}
}, rawType.getHitboxRadius(), false, filter);
);
return rVal;
}
@ -123,11 +129,15 @@ public class ProjectileUtils {
List<Entity> filter = new LinkedList<Entity>();
filter.add(parent);
//collidable
HitboxUtils.serverSpawnRegularHitbox(rVal, new HitboxPositionCallback() {
public Vector3d getPosition(){
return EntityUtils.getPosition(rVal);
HitboxData hitboxData = new HitboxData();
hitboxData.setRadius(rawType.getHitboxRadius());
HitboxState.attachHitboxStateWithCallback(realm.getHitboxManager(), realm.getCollisionEngine(), rVal, hitboxData,
new HitboxPositionCallback() {
public Vector3d getPosition(){
return EntityUtils.getPosition(rVal);
}
}
}, rawType.getHitboxRadius(), false, filter);
);
//position entity

View File

@ -5,8 +5,7 @@ import electrosphere.logger.LoggerInterface;
import electrosphere.util.FileUtils;
/**
*
* @author amaterasu
* User-defined settings
*/
public class UserSettings {
@ -41,7 +40,8 @@ public class UserSettings {
int renderResolutionY;
//debug
//debug visuals
boolean graphicsDebugDrawCollisionSpheres;
boolean graphicsDebugDrawCollisionSpheresClient;
boolean graphicsDebugDrawCollisionSpheresServer;
boolean graphicsDebugDrawPhysicsObjects;
boolean graphicsDebugDrawMovementVectors;
boolean graphicsDebugDrawNavmesh;
@ -82,8 +82,12 @@ public class UserSettings {
return graphicsPerformanceDrawShadows;
}
public boolean graphicsDebugDrawCollisionSpheres() {
return graphicsDebugDrawCollisionSpheres;
public boolean getGraphicsDebugDrawCollisionSpheresClient() {
return graphicsDebugDrawCollisionSpheresClient;
}
public boolean getGraphicsDebugDrawCollisionSpheresServer() {
return graphicsDebugDrawCollisionSpheresServer;
}
public boolean graphicsDebugDrawPhysicsObjects() {
@ -131,8 +135,12 @@ public class UserSettings {
}
public void setGraphicsDebugDrawCollisionSpheres(boolean draw){
this.graphicsDebugDrawCollisionSpheres = draw;
public void setGraphicsDebugDrawCollisionSpheresClient(boolean draw){
this.graphicsDebugDrawCollisionSpheresClient = draw;
}
public void setGraphicsDebugDrawCollisionSpheresServer(boolean draw){
this.graphicsDebugDrawCollisionSpheresServer = draw;
}
public void setGraphicsDebugDrawPhysicsObjects(boolean draw){
@ -178,7 +186,8 @@ public class UserSettings {
rVal.gameplayPhysicsCellRadius = 2;
//graphics settings
rVal.graphicsDebugDrawCollisionSpheres = false;
rVal.graphicsDebugDrawCollisionSpheresClient = false;
rVal.graphicsDebugDrawCollisionSpheresServer = false;
rVal.graphicsDebugDrawMovementVectors = false;
rVal.graphicsDebugDrawPhysicsObjects = false;
rVal.graphicsDebugDrawNavmesh = false;

View File

@ -4,25 +4,48 @@ import java.util.List;
import electrosphere.game.data.collidable.HitboxData;
/**
* Data about a weapon
*/
public class WeaponData {
//the class of weapon (ie sword, bow, etc)
String weaponClass;
//the hitboxes associated with the weapon
List<HitboxData> hitboxes;
//the damage the weapon does
int damage;
//the model for the projectile
String projectileModel;
/**
* Gets the weapon class
* @return the weapon class
*/
public String getWeaponClass(){
return weaponClass;
}
/**
* Gets the list of hitbox data
* @return the list of hitbox data
*/
public List<HitboxData> getHitboxes(){
return hitboxes;
}
/**
* Gets the projectile model
* @return the projectile model
*/
public String getProjectileModel(){
return projectileModel;
}
/**
* Gets the damage dealt
* @return the damage dealt
*/
public int getDamage(){
return damage;
}

View File

@ -10,6 +10,8 @@ import electrosphere.collision.PhysicsEntityUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.attack.ClientAttackTree;
import electrosphere.entity.state.server.ServerPlayerViewDirTree;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.renderer.RenderingEngine;
import electrosphere.renderer.ui.imgui.ImGuiLinePlot;
@ -172,16 +174,35 @@ public class ImGuiWindowMacros {
ImGui.text("Player Entity Details");
if(Globals.playerEntity != null){
ImGui.text("Position: " + EntityUtils.getPosition(Globals.playerEntity));
//server pos
int serverIdForClientEntity = Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId());
Entity serverPlayerEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
ImGui.text("Position (Server): " + EntityUtils.getPosition(serverPlayerEntity));
//client-side tree stuff
DBody body = PhysicsEntityUtils.getDBody(Globals.playerEntity);
ClientAttackTree attackTree = ClientAttackTree.getClientAttackTree(Globals.playerEntity);
if(body != null){
ImGui.text("Velocity: " + body.getLinearVel());
ImGui.text("Force: " + body.getForce());
ImGui.text("Angular Velocity: " + body.getAngularVel());
ImGui.text("Torque: " + body.getTorque());
ImGui.text("Move Vector: " + CreatureUtils.getFacingVector(Globals.playerEntity));
Entity serverEntity = EntityLookupUtils.getEntityById(Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId()));
ImGui.text("Move Vector (Server): " + CreatureUtils.getFacingVector(serverEntity));
if(attackTree != null){
ImGui.text("Attack Tree State: " + attackTree.getState());
}
}
//server-side tree stuff
DBody serverBody = PhysicsEntityUtils.getDBody(serverPlayerEntity);
if(body != null){
ImGui.text("Velocity (Server): " + serverBody.getLinearVel());
ImGui.text("Force (Server): " + serverBody.getForce());
ImGui.text("Move Vector (Server): " + CreatureUtils.getFacingVector(serverPlayerEntity));
ImGui.text("Velocity (Server): " + CreatureUtils.getVelocity(serverPlayerEntity));
}
ImGui.text("View dir (Server): " + ServerPlayerViewDirTree.getTree(serverPlayerEntity).getPlayerViewDir());
}
if(ImGui.button("Toggle Player Camera Lock")){
Globals.cameraHandler.setTrackPlayerEntity(!Globals.cameraHandler.getTrackPlayerEntity());

View File

@ -273,15 +273,27 @@ public class MenuGeneratorsInGame {
return false;
}});
//label (toggle draw collision spheres)
Button toggleCollisionSpheresButton = new Button();
Label toggleCollisionSpheresLabel = new Label(fontSize);
toggleCollisionSpheresLabel.setText("Toggle draw collision spheres");
toggleCollisionSpheresButton.addChild(toggleCollisionSpheresLabel);
scrollable.addChild(toggleCollisionSpheresButton);
toggleCollisionSpheresButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
//label (toggle draw client collision spheres)
Button toggleClientCollisionSpheresButton = new Button();
Label toggleClientCollisionSpheresLabel = new Label(fontSize);
toggleClientCollisionSpheresLabel.setText("Toggle draw client collision spheres");
toggleClientCollisionSpheresButton.addChild(toggleClientCollisionSpheresLabel);
scrollable.addChild(toggleClientCollisionSpheresButton);
toggleClientCollisionSpheresButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
// Main.running = false;
Globals.userSettings.setGraphicsDebugDrawCollisionSpheres(!Globals.userSettings.graphicsDebugDrawCollisionSpheres());
Globals.userSettings.setGraphicsDebugDrawCollisionSpheresClient(!Globals.userSettings.getGraphicsDebugDrawCollisionSpheresClient());
return false;
}});
//label (toggle draw server collision spheres)
Button toggleServerCollisionSpheresButton = new Button();
Label toggleServerCollisionSpheresLabel = new Label(fontSize);
toggleServerCollisionSpheresLabel.setText("Toggle draw server collision spheres");
toggleServerCollisionSpheresButton.addChild(toggleServerCollisionSpheresLabel);
scrollable.addChild(toggleServerCollisionSpheresButton);
toggleServerCollisionSpheresButton.setOnClick(new ClickableElement.ClickEventCallback(){public boolean execute(ClickEvent event){
// Main.running = false;
Globals.userSettings.setGraphicsDebugDrawCollisionSpheresServer(!Globals.userSettings.getGraphicsDebugDrawCollisionSpheresServer());
return false;
}});

View File

@ -143,6 +143,7 @@ public class EntityProtocol {
// TODO
//
//
case UPDATEENTITYVIEWDIR:
case KILL:
case SETPOSITION:
case SETFACING:

View File

@ -38,7 +38,7 @@ public class InventoryProtocol {
String equipPointName = message.getequipPointId();
EquipPoint equipPoint = equipState.getEquipPoint(equipPointName);
//attach
equipState.clientAttemptEquip(inWorldEntity, equipPoint);
equipState.attemptEquip(inWorldEntity, equipPoint);
}
}
break;

View File

@ -9,10 +9,13 @@ public class SynchronizationProtocol {
Globals.profiler.beginCpuSample("SynchronizationProtocol.handleSynchronizationMessage");
switch(message.getMessageSubtype()){
case UPDATECLIENTSTATE:
case UPDATECLIENTSTRINGSTATE:
case ATTACHTREE:
case DETATCHTREE:
Globals.clientSynchronizationManager.pushMessage(message);
break;
default:
throw new UnsupportedOperationException("Received synchronization message on the client of unsupported type: " + message.getMessageSubtype());
}
Globals.profiler.endCpuSample();
}

View File

@ -28,6 +28,7 @@ public class EntityMessage extends NetworkMessage {
SETBTREEPROPERTYENUM,
ATTACHENTITYTOENTITY,
SPAWNFOLIAGESEED,
UPDATEENTITYVIEWDIR,
}
EntityMessageType messageType;
@ -386,6 +387,12 @@ public class EntityMessage extends NetworkMessage {
return EntityMessage.canParseattachEntityToEntityMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED:
return EntityMessage.canParseSpawnFoliageSeedMessage(byteBuffer);
case TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR:
if(byteBuffer.getRemaining() >= TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR_SIZE){
return true;
} else {
return false;
}
}
return false;
}
@ -1010,6 +1017,28 @@ public class EntityMessage extends NetworkMessage {
return rVal;
}
public static EntityMessage parseupdateEntityViewDirMessage(CircularByteBuffer byteBuffer){
EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
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));
return rVal;
}
public static EntityMessage constructupdateEntityViewDirMessage(int entityID,long time,double positionX,double positionY,double positionZ){
EntityMessage rVal = new EntityMessage(EntityMessageType.UPDATEENTITYVIEWDIR);
rVal.setentityID(entityID);
rVal.settime(time);
rVal.setpositionX(positionX);
rVal.setpositionY(positionY);
rVal.setpositionZ(positionZ);
rVal.serialize();
return rVal;
}
@Override
void serialize(){
byte[] intValues = new byte[8];
@ -1566,6 +1595,33 @@ public class EntityMessage extends NetworkMessage {
rawBytes[34+creatureTemplate.length()+i] = intValues[i];
}
break;
case UPDATEENTITYVIEWDIR:
rawBytes = new byte[2+4+8+8+8+8];
//message header
rawBytes[0] = TypeBytes.MESSAGE_TYPE_ENTITY;
//entity messaage header
rawBytes[1] = TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR;
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];
}
break;
}
serialized = true;
}

View File

@ -141,6 +141,11 @@ SYNCHRONIZATION_MESSAGE,
rVal = EntityMessage.parseSpawnFoliageSeedMessage(byteBuffer);
}
break;
case TypeBytes.ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR:
if(EntityMessage.canParseMessage(byteBuffer,secondByte)){
rVal = EntityMessage.parseupdateEntityViewDirMessage(byteBuffer);
}
break;
}
break;
case TypeBytes.MESSAGE_TYPE_LORE:

View File

@ -37,6 +37,7 @@ Message categories
public static final byte ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYENUM = 17;
public static final byte ENTITY_MESSAGE_TYPE_ATTACHENTITYTOENTITY = 18;
public static final byte ENTITY_MESSAGE_TYPE_SPAWNFOLIAGESEED = 19;
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR = 20;
/*
Entity packet sizes
*/
@ -54,6 +55,7 @@ Message categories
public static final byte ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYFLOAT_SIZE = 26;
public static final byte ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYDOUBLE_SIZE = 30;
public static final byte ENTITY_MESSAGE_TYPE_SETBTREEPROPERTYENUM_SIZE = 26;
public static final byte ENTITY_MESSAGE_TYPE_UPDATEENTITYVIEWDIR_SIZE = 38;
/*
Lore subcategories
*/

View File

@ -1,24 +1,12 @@
package electrosphere.net.server.protocol;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.joml.Vector3i;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.ServerEntityUtils;
import electrosphere.entity.state.ironsight.IronSightTree;
import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.net.parser.net.message.CharacterMessage;
import electrosphere.net.parser.net.message.PlayerMessage;
import electrosphere.net.parser.net.message.TerrainMessage;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.Realm;
import electrosphere.server.character.PlayerCharacterCreation;
import electrosphere.util.Utilities;
public class CharacterProtocol {
@ -49,38 +37,12 @@ public class CharacterProtocol {
}
}
static void spawnPlayerCharacter(ServerConnectionHandler connectionHandler){
Player playerObject = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
//get template
CreatureTemplate template = connectionHandler.getCurrentCreatureTemplate();
String raceName = template.getCreatureType();
//spawn player in world
Realm realm = Globals.realmManager.getRealms().iterator().next();
Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(Globals.spawnPoint.x,Globals.spawnPoint.y,Globals.spawnPoint.z),raceName,template);
int playerCharacterId = newPlayerEntity.getId();
connectionHandler.setPlayerCharacterId(playerCharacterId);
CreatureUtils.setControllerPlayerId(newPlayerEntity, connectionHandler.getPlayerId());
//attach player object to player character
playerObject.setPlayerEntity(newPlayerEntity);
playerObject.setWorldPos(new Vector3i(
Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x),
Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.y),
Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z)
));
// System.out.println(EntityUtils.getRotation(newPlayerCharacter).set(0,1,0,1).normalize());
realm.getDataCellManager().addPlayerToRealm(playerObject);
// IronSightTree.attachIronSightTree(newPlayerEntity);
// //spawn player sword
// Entity sword = ItemUtils.spawnBasicItem("Katana");
// AttachUtils.attachEntityToEntityAtBone(newPlayerCharacter, sword, "Bone.031");
//set controller id
if(playerObject == Globals.clientPlayer){
Globals.playerEntity = newPlayerEntity;
}
}
/**
* Spawns the player's entity
* @param connectionHandler The connection handler for the player
*/
static void spawnClientEntity(ServerConnectionHandler connectionHandler){
spawnPlayerCharacter(connectionHandler);
PlayerCharacterCreation.spawnPlayerCharacter(connectionHandler);
//set client initial discrete position
connectionHandler.addMessagetoOutgoingQueue(
PlayerMessage.constructSetInitialDiscretePositionMessage(
@ -93,8 +55,6 @@ public class CharacterProtocol {
connectionHandler.addMessagetoOutgoingQueue(
TerrainMessage.constructSpawnPositionMessage(Globals.spawnPoint.x, Globals.spawnPoint.y, Globals.spawnPoint.z)
);
//tell them what player stats they are
// connectionHandler.addMessagetoOutgoingQueue(PlayerMessage.constructSet_IDMessage(connectionHandler.getPlayerCharacterId()));
}
}

View File

@ -1,15 +1,11 @@
package electrosphere.net.server.protocol;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import org.joml.Vector3d;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.attack.ServerAttackTree;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.state.server.ServerPlayerViewDirTree;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.logger.LoggerInterface;
import electrosphere.net.NetUtils;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.server.datacell.utils.EntityLookupUtils;
@ -45,6 +41,12 @@ public class EntityProtocol {
ServerAttackTree.getServerAttackTree(targetEntity).addNetworkMessage(message);
}
} break;
case UPDATEENTITYVIEWDIR: {
targetEntity = EntityLookupUtils.getEntityById(message.getentityID());
if(targetEntity != null && ServerPlayerViewDirTree.hasTree(targetEntity)){
ServerPlayerViewDirTree.getTree(targetEntity).setPlayerViewDir(new Vector3d(message.getpositionX(),message.getpositionY(),message.getpositionZ()),message.gettime());
}
} break;
//ignore stack
case KILL:
case SPAWNCREATURE:
@ -54,6 +56,13 @@ public class EntityProtocol {
case SETFACING:
case SETPOSITION:
case SETPROPERTY:
case SETBTREEPROPERTYDOUBLE:
case SETBTREEPROPERTYENUM:
case SETBTREEPROPERTYFLOAT:
case SETBTREEPROPERTYINT:
case SETBTREEPROPERTYSTRING:
case SPAWNFOLIAGESEED:
case SPAWNITEM:
//silently ignore
break;
}

View File

@ -92,7 +92,15 @@ public class Actor {
return -1.0f;
}
/**
* Checks if an animation is being played on any meshes
* @param animationName The animation name
* @return true if the animation is being played on any meshes, false if the provided animation name is null or the animation is not being played on any meshes
*/
public boolean isPlayingAnimation(String animationName){
if(animationName == null){
return false;
}
for(ActorAnimationMask mask : animationQueue){
if(mask.getAnimationName().contains(animationName)){
return true;
@ -255,6 +263,12 @@ public class Actor {
return modelPath;
}
/**
* Gets the position of a bone
* @param boneName The name of the bone
* @return The vector3f containing the position of the bone, or a vector of (0,0,0) if the model lookup fails
* //TODO: refactor to make failure more transparent (both for model not existing and bone not existing)
*/
public Vector3f getBonePosition(String boneName){
Vector3f rVal = new Vector3f();
Model model = Globals.assetManager.fetchModel(modelPath);

View File

@ -5,12 +5,15 @@ import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
/**
*
* @author amaterasu
* Utils for dealing with actors
*/
public class ActorUtils {
/**
* Creates an actor object and queues the model path
* @param modelPath The model path
* @return The actor object
*/
public static Actor createActorFromModelPath(String modelPath){
Actor rVal = new Actor(modelPath);
Globals.assetManager.addModelPathToQueue(modelPath);
@ -24,7 +27,7 @@ public class ActorUtils {
@Deprecated
public static void applyBlenderTransformer(Entity actorEntity){
Actor entityActor = EntityUtils.getActor(actorEntity);
// Actor entityActor = EntityUtils.getActor(actorEntity);
// entityActor.setAnimationScalar(60f); //should be the value of the fps i think
}

View File

@ -6,20 +6,24 @@ import org.joml.Quaternionf;
import org.joml.Vector3d;
import org.joml.Vector3f;
import org.lwjgl.opengl.GL40;
import org.ode4j.ode.DGeom;
import org.ode4j.ode.DSphere;
import electrosphere.collision.PhysicsUtils;
import electrosphere.collision.collidable.Collidable;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.hitbox.HitboxState;
import electrosphere.entity.types.camera.CameraEntityUtils;
import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.renderer.OpenGLState;
import electrosphere.renderer.RenderPipelineState;
import electrosphere.renderer.RenderingEngine;
import electrosphere.renderer.model.Model;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.EntityLookupUtils;
import electrosphere.server.pathfinding.navmesh.NavCube;
import electrosphere.server.pathfinding.navmesh.NavMesh;
import electrosphere.server.pathfinding.navmesh.NavShape;
@ -56,44 +60,89 @@ public class DebugContentPipeline implements RenderPipeline {
Matrix4d modelTransformMatrix = new Matrix4d();
if(Globals.userSettings.graphicsDebugDrawCollisionSpheres()){
for(Entity currentHitbox : Globals.clientHitboxManager.getAllHitboxes()){
if((boolean)currentHitbox.getData(EntityDataStrings.DATA_STRING_DRAW)){
Model hitboxModel;
HitboxData data = HitboxUtils.getHitboxData(currentHitbox);
if(data.isActive()){
if(data.getType().equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere.fbx")) != null){
Vector3d position = EntityUtils.getPosition(currentHitbox);
//calculate camera-modified vector3f
Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
// modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
modelTransformMatrix.scale(data.getRadius() * 2);
hitboxModel.setModelMatrix(modelTransformMatrix);
hitboxModel.draw(renderPipelineState,openGLState);
}
} else if(data.getType().equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere_1.fbx")) != null){
Vector3d position = EntityUtils.getPosition(currentHitbox);
//calculate camera-modified vector3f
Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
// modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
modelTransformMatrix.scale(data.getRadius() * 2);
hitboxModel.setModelMatrix(modelTransformMatrix);
hitboxModel.draw(renderPipelineState,openGLState);
}
}
} else {
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere_grey.fbx")) != null){
Vector3d position = EntityUtils.getPosition(currentHitbox);
if(Globals.userSettings.getGraphicsDebugDrawCollisionSpheresClient()){
Model hitboxModel;
for(HitboxState hitboxState : Globals.clientSceneWrapper.getHitboxManager().getAllHitboxes()){
for(String boneName : hitboxState.getBones()){
DGeom geom = hitboxState.getGeometry(boneName);
if(geom instanceof DSphere){
DSphere sphereView = (DSphere)geom;
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere.glb")) != null){
Vector3d position = PhysicsUtils.odeVecToJomlVec(sphereView.getPosition());
//calculate camera-modified vector3f
Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
modelTransformMatrix.identity();
modelTransformMatrix.translate(new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)));
modelTransformMatrix.translate(cameraModifiedPosition);
// modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
modelTransformMatrix.scale(data.getRadius() * 2);
modelTransformMatrix.scale(sphereView.getRadius() * 2);
hitboxModel.setModelMatrix(modelTransformMatrix);
hitboxModel.draw(renderPipelineState,openGLState);
}
}
}
}
// for(Entity currentHitbox : Globals.clientHitboxManager.getAllHitboxes()){
// if((boolean)currentHitbox.getData(EntityDataStrings.DATA_STRING_DRAW)){
// Model hitboxModel;
// HitboxData data = HitboxUtils.getHitboxData(currentHitbox);
// if(data.isActive()){
// if(data.getType().equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){
// if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere.fbx")) != null){
// Vector3d position = EntityUtils.getPosition(currentHitbox);
// //calculate camera-modified vector3f
// Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
// modelTransformMatrix.identity();
// modelTransformMatrix.translate(cameraModifiedPosition);
// // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
// modelTransformMatrix.scale(data.getRadius() * 2);
// hitboxModel.setModelMatrix(modelTransformMatrix);
// hitboxModel.draw(renderPipelineState,openGLState);
// }
// } else if(data.getType().equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){
// if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere_1.fbx")) != null){
// Vector3d position = EntityUtils.getPosition(currentHitbox);
// //calculate camera-modified vector3f
// Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
// modelTransformMatrix.identity();
// modelTransformMatrix.translate(cameraModifiedPosition);
// // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
// modelTransformMatrix.scale(data.getRadius() * 2);
// hitboxModel.setModelMatrix(modelTransformMatrix);
// hitboxModel.draw(renderPipelineState,openGLState);
// }
// }
// } else {
// if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere_grey.fbx")) != null){
// Vector3d position = EntityUtils.getPosition(currentHitbox);
// modelTransformMatrix.identity();
// modelTransformMatrix.translate(new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)));
// // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
// modelTransformMatrix.scale(data.getRadius() * 2);
// hitboxModel.setModelMatrix(modelTransformMatrix);
// hitboxModel.draw(renderPipelineState,openGLState);
// }
// }
// }
// }
}
if(Globals.userSettings.getGraphicsDebugDrawCollisionSpheresServer()){
Model hitboxModel;
int serverIdForClientEntity = Globals.clientSceneWrapper.mapClientToServerId(Globals.playerEntity.getId());
Entity serverPlayerEntity = EntityLookupUtils.getEntityById(serverIdForClientEntity);
Realm playerRealm = Globals.realmManager.getEntityRealm(serverPlayerEntity);
for(HitboxState hitboxState : playerRealm.getHitboxManager().getAllHitboxes()){
for(String boneName : hitboxState.getBones()){
DGeom geom = hitboxState.getGeometry(boneName);
if(geom instanceof DSphere){
DSphere sphereView = (DSphere)geom;
if((hitboxModel = Globals.assetManager.fetchModel("Models/basic/geometry/unitsphere.glb")) != null){
Vector3d position = PhysicsUtils.odeVecToJomlVec(sphereView.getPosition());
//calculate camera-modified vector3f
Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
modelTransformMatrix.identity();
modelTransformMatrix.translate(cameraModifiedPosition);
// modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
modelTransformMatrix.scale(sphereView.getRadius() * 2);
hitboxModel.setModelMatrix(modelTransformMatrix);
hitboxModel.draw(renderPipelineState,openGLState);
}

View File

@ -43,7 +43,9 @@ public class FirstPersonItemsPipeline implements RenderPipeline {
public void render(OpenGLState openGLState, RenderPipelineState renderPipelineState) {
//update logic
updateFirstPersonModelPosition(Globals.firstPersonEntity);
if(Globals.firstPersonEntity != null){
updateFirstPersonModelPosition(Globals.firstPersonEntity);
}
//setup opengl state
this.firstPersonFramebuffer.bind();

View File

@ -0,0 +1,59 @@
package electrosphere.server.character;
import org.joml.Vector3d;
import org.joml.Vector3i;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.state.server.ServerPlayerViewDirTree;
import electrosphere.entity.types.creature.CreatureTemplate;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.net.server.ServerConnectionHandler;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.Realm;
/**
* Deals with spawning player characters
*/
public class PlayerCharacterCreation {
/**
* Spawns the player's character
* @param connectionHandler The connection handler of the player
*/
public static void spawnPlayerCharacter(ServerConnectionHandler connectionHandler){
Player playerObject = Globals.playerManager.getPlayerFromId(connectionHandler.getPlayerId());
//get template
CreatureTemplate template = connectionHandler.getCurrentCreatureTemplate();
String raceName = template.getCreatureType();
//spawn entity in world
Realm realm = Globals.realmManager.getRealms().iterator().next();
Entity newPlayerEntity = CreatureUtils.serverSpawnBasicCreature(realm,new Vector3d(Globals.spawnPoint.x,Globals.spawnPoint.y,Globals.spawnPoint.z),raceName,template);
int playerCharacterId = newPlayerEntity.getId();
connectionHandler.setPlayerCharacterId(playerCharacterId);
CreatureUtils.setControllerPlayerId(newPlayerEntity, connectionHandler.getPlayerId());
//custom player btrees
addPlayerServerBTrees(newPlayerEntity);
//attach player object to player character
playerObject.setPlayerEntity(newPlayerEntity);
playerObject.setWorldPos(new Vector3i(
Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.x),
Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.y),
Globals.serverWorldData.convertRealToChunkSpace(Globals.spawnPoint.z)
));
realm.getDataCellManager().addPlayerToRealm(playerObject);
//set controller id
if(playerObject == Globals.clientPlayer){
Globals.playerEntity = newPlayerEntity;
}
}
/**
* Adds behavior trees that are unique to players a given entity
* @param entity The entity to add to
*/
static void addPlayerServerBTrees(Entity entity){
ServerPlayerViewDirTree.attachServerPlayerViewDirTree(entity);
}
}

View File

@ -154,15 +154,22 @@ public class Realm {
* Tells the data cell manager to simulate all loaded cells
*/
protected void simulate(){
//
//simulate bullet physics engine step
collisionEngine.simulatePhysics((float)Globals.timekeeper.getSimFrameTime());
collisionEngine.updateDynamicObjectTransforms();
//
//hitbox sim
hitboxManager.simulate();
//
//main simulation
dataCellManager.simulate();
//
//data cell manager update misc variables (player positions, unload not-in-use cells)
if(dataCellManager != null){
dataCellManager.unloadPlayerlessChunks();
}
//
//clear collidable impulse lists
collisionEngine.clearCollidableImpulseLists();
}

View File

@ -12,6 +12,7 @@ import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.game.server.world.ServerWorldData;
import electrosphere.net.server.player.Player;
import electrosphere.server.datacell.physics.ServerHitboxResolutionCallback;
/**
* Manages all realms for the engine. Should be a singleton
@ -39,7 +40,7 @@ public class RealmManager {
* @return The realm
*/
public Realm createRealm(){
return new Realm(new CollisionEngine(), new HitboxManager());
return new Realm(new CollisionEngine(), new HitboxManager(new ServerHitboxResolutionCallback()));
}
/**
@ -51,7 +52,7 @@ public class RealmManager {
CollisionEngine collisionEngine = new CollisionEngine();
collisionEngine.setCollisionWorldData(new CollisionWorldData(serverWorldData));
//create realm
Realm realm = new Realm(collisionEngine, new HitboxManager());
Realm realm = new Realm(collisionEngine, new HitboxManager(new ServerHitboxResolutionCallback()));
//create function classes
GriddedDataCellManager griddedDataCellManager = new GriddedDataCellManager(realm,Globals.serverTerrainManager,Globals.serverFluidManager,Globals.serverContentManager);
EntityDataCellMapper entityDataCellMapper = new EntityDataCellMapper();

View File

@ -0,0 +1,88 @@
package electrosphere.server.datacell.physics;
import org.joml.Vector3d;
import org.ode4j.ode.DContactGeom;
import org.ode4j.ode.DGeom;
import electrosphere.collision.CollisionEngine.CollisionResolutionCallback;
import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.hitbox.HitboxState;
import electrosphere.entity.state.hitbox.HitboxState.HitboxShapeStatus;
import electrosphere.entity.state.hitbox.HitboxState.HitboxType;
import electrosphere.entity.state.life.LifeUtils;
import electrosphere.entity.state.movement.ProjectileTree;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.server.datacell.Realm;
import electrosphere.server.datacell.utils.DataCellSearchUtils;
/**
* Callback for managing collisions on the server
*/
public class ServerHitboxResolutionCallback implements CollisionResolutionCallback {
@Override
public void resolve(DContactGeom contactGeom, Collidable impactor, Collidable receiver, Vector3d normal, Vector3d localPosition, Vector3d worldPos, float magnitude) {
Entity impactorParent = impactor.getParent();
Entity receiverParent = receiver.getParent();
HitboxState impactorState = HitboxState.getHitboxState(impactorParent);
HitboxState receiverState = HitboxState.getHitboxState(receiverParent);
DGeom impactorGeom = contactGeom.g1;
DGeom receiverGeom = contactGeom.g2;
HitboxShapeStatus impactorShapeStatus = impactorState.getShapeStatus(impactorGeom);
HitboxShapeStatus receiverShapeStatus = receiverState.getShapeStatus(receiverGeom);
Realm receiverRealm = Globals.realmManager.getEntityRealm(receiverParent);
//currently, impactor needs to be an item, and the receiver must not be an item
boolean isDamageEvent =
impactorShapeStatus != null &&
receiverShapeStatus != null &&
impactorShapeStatus.isActive() &&
receiverShapeStatus.isActive() &&
impactorShapeStatus.getType() == HitboxType.HIT &&
receiverShapeStatus.getType() == HitboxType.HURT &&
AttachUtils.getParent(impactorParent) != receiverParent
;
if(isDamageEvent){
//if the entity is attached to is an item, we need to compare with the parent of the item
//to make sure you don't stab yourself for instance
boolean isItem = ItemUtils.isItem(impactorParent);//hitboxParent.containsKey(EntityDataStrings.ITEM_IS_ITEM);
Entity hitboxAttachParent = AttachUtils.getParent(impactorParent);
if(isItem){
if(hitboxAttachParent != receiverParent){
int damage = ItemUtils.getWeaponDataRaw(impactorParent).getDamage();
LifeUtils.getLifeState(receiverParent).damage(damage);
if(!LifeUtils.getLifeState(receiverParent).isIsAlive()){
EntityUtils.getPosition(receiverParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(receiverParent).revive();
}
}
} else {
int damage = 0;
//for entities using attacktree
if(CreatureUtils.serverGetAttackTree(impactorParent) != null){
damage = ItemUtils.getWeaponDataRaw(impactorParent).getDamage();
} else {
//for entities using shooter tree
if(ProjectileTree.getProjectileTree(impactorParent) != null){
damage = (int)ProjectileTree.getProjectileTree(impactorParent).getDamage();
}
}
LifeUtils.getLifeState(receiverParent).damage(damage);
if(!LifeUtils.getLifeState(receiverParent).isIsAlive()){
EntityUtils.getPosition(receiverParent).set(Globals.spawnPoint);
LifeUtils.getLifeState(receiverParent).revive();
}
}
}
}
}

View File

@ -12,13 +12,11 @@ import org.joml.Matrix4f;
import org.joml.Quaterniond;
import org.joml.Vector3f;
import org.joml.Vector4d;
import org.joml.Vector4f;
import electrosphere.engine.Globals;
import electrosphere.renderer.actor.ActorAnimationMask;
import electrosphere.renderer.actor.ActorBoneRotator;
import electrosphere.renderer.actor.ActorStaticMorph;
import electrosphere.renderer.actor.ActorStaticMorph.StaticMorphTransforms;
import electrosphere.renderer.model.Bone;
/**

View File

@ -1,10 +1,21 @@
package electrosphere.server.poseactor;
import electrosphere.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityUtils;
public class PoseActorUtils {
/**
* Creates a pose actor object and queues the model path
* @param modelPath The model path
* @return The PoseActor object
*/
public static PoseActor createPoseActorFromModelPath(String modelPath){
PoseActor rVal = new PoseActor(modelPath);
Globals.assetManager.addPoseModelPathToQueue(modelPath);
return rVal;
}
public static void applyBlenderTransformer(Entity actorEntity){
PoseActor entityActor = EntityUtils.getPoseActor(actorEntity);

View File

@ -1,41 +1,20 @@
package electrosphere.server.simulation;
import electrosphere.entity.types.attach.AttachUtils;
import electrosphere.client.targeting.crosshair.Crosshair;
import electrosphere.collision.hitbox.HitboxManager;
import electrosphere.collision.hitbox.HitboxUtils;
import electrosphere.engine.Globals;
import electrosphere.engine.Main;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityTags;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.scene.EntityDescriptor;
import electrosphere.entity.state.ParticleTree;
import electrosphere.entity.state.attack.ClientAttackTree;
import electrosphere.entity.state.collidable.ClientCollidableTree;
import electrosphere.entity.state.collidable.ServerCollidableTree;
import electrosphere.entity.state.idle.IdleTree;
import electrosphere.entity.types.creature.CreatureUtils;
import electrosphere.entity.types.item.ItemUtils;
import electrosphere.entity.state.life.LifeState;
import electrosphere.entity.state.life.LifeUtils;
import electrosphere.entity.state.movement.SprintTree;
import electrosphere.entity.state.movement.groundmove.ClientGroundMovementTree;
import electrosphere.entity.types.particle.ParticleUtils;
import electrosphere.net.parser.net.message.EntityMessage;
import electrosphere.renderer.actor.Actor;
import electrosphere.server.datacell.ServerDataCell;
import java.sql.Time;
import org.joml.Vector3d;
import org.joml.Vector3f;
/**
*
* @author amaterasu
* Server-side micro-scale simulation
*/
public class MicroSimulation {
@ -79,16 +58,9 @@ public class MicroSimulation {
}
//update attached entity positions
AttachUtils.serverUpdateAttachedEntityPositions(dataCell);
//update hitbox positions
for(Entity currentHitbox : hitboxManager.getAllHitboxes()){
HitboxUtils.serverUpdatePosition(currentHitbox);
}
//collide hitboxes
for(Entity currentHitbox : hitboxManager.getAllHitboxes()){
if(isReady){
HitboxUtils.serverCollideEntities(currentHitbox);
}
}
//
//hitbox updates
hitboxManager.simulate();
//simulate behavior trees
dataCell.getScene().simulateBehaviorTrees((float)Globals.timekeeper.getSimFrameTime());
//sum collidable impulses