Renderer/src/main/java/electrosphere/entity/state/hitbox/HitboxCollectionState.java
austin 9a20a64d5b
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit
fixing up gridded data cell manager
2024-11-13 21:08:32 -05:00

945 lines
35 KiB
Java

package electrosphere.entity.state.hitbox;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
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.engine.Globals;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.attach.AttachUtils;
import electrosphere.entity.state.hitbox.HitboxCollectionState.HitboxState.HitboxShapeType;
import electrosphere.game.data.collidable.HitboxData;
import electrosphere.game.data.utils.DataFormatUtil;
import electrosphere.logger.LoggerInterface;
import electrosphere.server.datacell.Realm;
import electrosphere.util.math.SpatialMathUtils;
/**
* The state of the collection of all hitboxes on this entity
* Ie, it stores the state of each hitbox that is attached to this entity
*/
public class HitboxCollectionState {
/**
* Types of hitboxes
*/
public enum HitboxType {
HIT, // damages another entity
HURT, // receives damage from another entity
BLOCK, // blocks a hit from another entity
}
/**
* The subtype of hitbox
*/
public enum HitboxSubtype {
SWEET, //extra damage
REGULAR, //regular damage
SOUR, //less damage
}
//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 list of all geoms in the collection state
List<DGeom> geoms = new LinkedList<DGeom>();
//the map of bone -> list of states of individual shapes attached to that bone
Map<String,List<HitboxState>> boneHitboxMap = new HashMap<String,List<HitboxState>>();
//map of hitbox state -> geometry
Map<HitboxState,DGeom> stateGeomMap = new HashMap<HitboxState,DGeom>();
//the map of geometry -> hitbox shape status, useful for finding data about a given hitbox during collision
Map<DGeom,HitboxState> geomStateMap = new HashMap<DGeom,HitboxState>();
/**
* The list of all hitbox states
*/
List<HitboxState> allStates = new LinkedList<HitboxState>();
/**
* The list of non-bone hitboxes
*/
List<HitboxState> nonBoneHitboxes = new LinkedList<HitboxState>();
//callback to provide a position for the hitbox each frame
HitboxPositionCallback positionCallback;
//controls whether the hitbox state is active or not
boolean active = true;
//controls whether active hitboxes should be overwritten with block boxes
boolean blockOverride = false;
//the associated manager
HitboxManager manager;
//controls whether this hitbox collection thinks its on the server or client
boolean isServer = true;
/**
* 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 HitboxCollectionState attachHitboxState(HitboxManager manager, boolean isServer, Entity entity, List<HitboxData> hitboxListRaw){
HitboxCollectionState rVal = new HitboxCollectionState();
rVal.isServer = isServer;
//create the shapes
for(HitboxData hitboxDataRaw : hitboxListRaw){
DGeom geom = null;
HitboxType type = HitboxType.HIT;
HitboxShapeType shapeType = HitboxShapeType.SPHERE;
//
//Get the type as an enum
//
switch(hitboxDataRaw.getType()){
case HitboxData.HITBOX_TYPE_HIT: {
type = HitboxType.HIT;
shapeType = HitboxShapeType.SPHERE;
geom = CollisionBodyCreation.createShapeSphere(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), Collidable.TYPE_OBJECT_BIT);
} break;
case HitboxData.HITBOX_TYPE_HURT: {
type = HitboxType.HURT;
shapeType = HitboxShapeType.SPHERE;
geom = CollisionBodyCreation.createShapeSphere(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), Collidable.TYPE_OBJECT_BIT);
} break;
case HitboxData.HITBOX_TYPE_HIT_CONNECTED: {
type = HitboxType.HIT;
shapeType = HitboxShapeType.CAPSULE;
geom = CollisionBodyCreation.createShapeSphere(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), Collidable.TYPE_OBJECT_BIT);
} break;
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
type = HitboxType.HURT;
shapeType = HitboxShapeType.CAPSULE;
geom = CollisionBodyCreation.createShapeSphere(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), Collidable.TYPE_OBJECT_BIT);
} break;
case HitboxData.HITBOX_TYPE_STATIC_CAPSULE: {
type = HitboxType.HURT;
shapeType = HitboxShapeType.STATIC_CAPSULE;
geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), hitboxDataRaw.getRadius(), hitboxDataRaw.getLength(), Collidable.TYPE_OBJECT_BIT);
} break;
}
//
//Get the subtype as an enum
//
HitboxSubtype subType;
String subTypeRaw = hitboxDataRaw.getSubType();
if(subTypeRaw == null){
subTypeRaw = HitboxData.HITBOX_SUBTYPE_REUGLAR;
}
switch(subTypeRaw){
case HitboxData.HITBOX_SUBTYPE_SWEET: {
subType = HitboxSubtype.SWEET;
} break;
case HitboxData.HITBOX_SUBTYPE_REUGLAR: {
subType = HitboxSubtype.REGULAR;
} break;
case HitboxData.HITBOX_SUBTYPE_SOUR: {
subType = HitboxSubtype.SOUR;
} break;
default: {
subType = HitboxSubtype.REGULAR;
} break;
}
//create the state for the individual shape
HitboxState state = new HitboxState(hitboxDataRaw.getBone(), hitboxDataRaw, type, subType, shapeType, false);
//add to structures
if(hitboxDataRaw.getBone() != null){
rVal.addHitbox(hitboxDataRaw.getBone(),state);
} else {
rVal.addHitbox(state);
}
rVal.registerGeom(geom,state);
}
//create body with all the shapes
DGeom[] geomArray = rVal.geoms.toArray(new DGeom[rVal.geoms.size()]);
rVal.body = CollisionBodyCreation.createBodyWithShapes(manager.getCollisionEngine(), geomArray);
//register collidable with collision engine
Collidable collidable = new Collidable(entity, Collidable.TYPE_OBJECT, true);
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 HitboxCollectionState attachHitboxStateWithCallback(HitboxManager manager, CollisionEngine collisionEngine, Entity entity, HitboxData data, HitboxPositionCallback callback){
throw new UnsupportedOperationException("Not yet implemented!");
// HitboxCollectionState rVal = new HitboxCollectionState();
// //create the shapes
// DGeom geom = CollisionBodyCreation.createShapeSphere(collisionEngine, data.getRadius(), Collidable.TYPE_OBJECT_BIT);
// //create the state for the individual shape
// HitboxState state = new HitboxState(data.getBone(), data, getType(data), getSubType(data), getShapeType(data), false);
// rVal.addHitbox(data.getBone(), state);
// rVal.registerGeom(geom,state);
// //create body with all the shapes
// DGeom[] geomArray = rVal.geoms.toArray(new DGeom[rVal.geoms.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;
}
/**
* Clears the collision status of all shapes
*/
public void clearCollisions(){
for(DGeom geom : this.geoms){
HitboxState shapeStatus = this.geomStateMap.get(geom);
shapeStatus.setHadCollision(false);
}
}
/**
* Updates the positions of all hitboxes
*/
public void updateHitboxPositions(CollisionEngine collisionEngine){
if(parent != null && !isServer && EntityUtils.getActor(parent) != null){
if(!this.geoms.isEmpty()){
Vector3d entityPosition = EntityUtils.getPosition(parent);
this.body.setPosition(PhysicsUtils.jomlVecToOdeVec(entityPosition));
for(String boneName : this.boneHitboxMap.keySet()){
if(EntityUtils.getActor(parent).containsBone(boneName)){
Vector3f bonePosition = EntityUtils.getActor(parent).getBonePosition(boneName);
for(HitboxState state : this.boneHitboxMap.get(boneName)){
DGeom geom = this.stateGeomMap.get(state);
HitboxState shapeStatus = this.geomStateMap.get(geom);
switch(shapeStatus.shapeType){
case SPHERE: {
this.updateSphereShapePosition(collisionEngine,boneName,shapeStatus,bonePosition);
} break;
case CAPSULE: {
this.updateCapsuleShapePosition(collisionEngine,boneName,shapeStatus,bonePosition);
} break;
case STATIC_CAPSULE: {
} break;
}
}
}
}
for(HitboxState state : this.nonBoneHitboxes){
DGeom geom = this.stateGeomMap.get(state);
HitboxState shapeStatus = this.geomStateMap.get(geom);
switch(shapeStatus.shapeType){
case SPHERE: {
this.updateSphereShapePosition(collisionEngine,null,shapeStatus,null);
} break;
case CAPSULE: {
this.updateCapsuleShapePosition(collisionEngine,null,shapeStatus,null);
} break;
case STATIC_CAPSULE: {
} break;
}
}
}
//update bone-attached hitboxes on server
} else if(parent != null && isServer && EntityUtils.getPoseActor(parent) != null){
if(!this.geoms.isEmpty()){
Vector3d entityPosition = EntityUtils.getPosition(parent);
this.body.setPosition(PhysicsUtils.jomlVecToOdeVec(entityPosition));
//
for(String boneName : this.boneHitboxMap.keySet()){
if(EntityUtils.getPoseActor(parent).containsBone(boneName)){
Vector3f bonePosition = EntityUtils.getPoseActor(parent).getBonePosition(boneName);
//
for(HitboxState state : this.boneHitboxMap.get(boneName)){
if(state == null){
throw new IllegalStateException("Geometry not assigned to a hitbox state!");
}
//
switch(state.shapeType){
case SPHERE: {
this.updateSphereShapePosition(collisionEngine,boneName,state,bonePosition);
} break;
case CAPSULE: {
this.updateCapsuleShapePosition(collisionEngine,boneName,state,bonePosition);
} break;
case STATIC_CAPSULE: {
} break;
}
}
}
}
for(HitboxState state : this.nonBoneHitboxes){
DGeom geom = this.stateGeomMap.get(state);
HitboxState shapeStatus = this.geomStateMap.get(geom);
switch(shapeStatus.shapeType){
case SPHERE: {
this.updateSphereShapePosition(collisionEngine,null,shapeStatus,null);
} break;
case CAPSULE: {
this.updateCapsuleShapePosition(collisionEngine,null,shapeStatus,null);
} break;
case STATIC_CAPSULE: {
} break;
}
}
}
//update non-bone attached static objects on server
} else if(parent != null && isServer){
for(DGeom geom : this.geoms){
HitboxState shapeStatus = this.geomStateMap.get(geom);
switch(shapeStatus.shapeType){
case SPHERE: {
this.updateSphereShapePosition(collisionEngine,null,shapeStatus,null);
} break;
case CAPSULE: {
this.updateCapsuleShapePosition(collisionEngine,null,shapeStatus,null);
} break;
case STATIC_CAPSULE: {
this.updateStaticCapsulePosition(collisionEngine, geom, shapeStatus);
} break;
}
}
}
}
/**
* Updates the position of the geom for a static capsule
* @param collisionEngine The collision engine
* @param boneName The name of the bone the static capsule is attached to
* @param bonePosition The position of the bone
*/
private void updateStaticCapsulePosition(CollisionEngine collisionEngine, DGeom geom, HitboxState shapeStatus){
Vector3d parentPos = EntityUtils.getPosition(parent);
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, parentPos, new Quaterniond(0.707,0,0,0.707));
}
/**
* Updates the position of a sphere-shape-type hitbox
* @param collisionEngine The collision engine
* @param boneName The name of the bone
* @param bonePosition the position of the bone
*/
private void updateSphereShapePosition(CollisionEngine collisionEngine, String boneName, HitboxState hitboxState, Vector3f bonePosition){
DGeom geom = this.stateGeomMap.get(hitboxState);
//get offset's transform
Vector3d offsetPosition = DataFormatUtil.getDoubleListAsVector(hitboxState.getHitboxData().getOffset());
Quaterniond offsetRotation = new Quaterniond();
//the bone's transform
Vector3d bonePositionD = new Vector3d();
if(bonePosition != null){
bonePositionD = new Vector3d(bonePosition);
}
Quaterniond boneRotation = new Quaterniond();
//the parent's transform
Vector3d parentPosition = EntityUtils.getPosition(parent);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3d parentScale = new Vector3d(EntityUtils.getScale(parent));
//calculate
Vector3d hitboxPos = AttachUtils.calculateBoneAttachmentPosition(offsetPosition, offsetRotation, bonePositionD, boneRotation, parentPosition, parentRotation, parentScale);
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, hitboxPos, new Quaterniond());
}
/**
* Updates the position of a capsule-shape hitbox
* @param collisionEngine
* @param boneName
* @param bonePosition
*/
private void updateCapsuleShapePosition(CollisionEngine collisionEngine, String boneName, HitboxState hitboxState, Vector3f bonePosition){
//get data about the hitbox
DGeom geom = this.stateGeomMap.get(hitboxState);
Vector3d previousWorldPos = hitboxState.getPreviousWorldPos();
double length = hitboxState.getHitboxData().getRadius();
//get offset's transform
Vector3d offsetPosition = DataFormatUtil.getDoubleListAsVector(hitboxState.getHitboxData().getOffset());
Quaterniond offsetRotation = new Quaterniond();
//the bone's transform
Vector3d bonePositionD = new Vector3d();
if(bonePosition != null){
bonePositionD = new Vector3d(bonePosition);
}
Quaterniond boneRotation = new Quaterniond();
//the parent's transform
Vector3d parentPosition = EntityUtils.getPosition(parent);
Quaterniond parentRotation = EntityUtils.getRotation(parent);
Vector3d parentScale = new Vector3d(EntityUtils.getScale(parent));
//calculate
Vector3d worldPosition = AttachUtils.calculateBoneAttachmentPosition(offsetPosition, offsetRotation, bonePositionD, boneRotation, parentPosition, parentRotation, parentScale);
Quaterniond worldRotation = new Quaterniond();
if(previousWorldPos != null){
//called all subsequent updates to hitbox position
//destroy old capsule
this.destroyGeom(collisionEngine, geom);
//calculate position between new world point and old world point
Vector3d bodyPosition = new Vector3d(worldPosition).lerp(previousWorldPos, 0.5);
//calculate rotation from old position to new position
//the second quaternion is a rotation along the x axis. This is used to put the hitbox rotation into ode's space
//ode is Z-axis-up
if(previousWorldPos.distance(worldPosition) > 0.0){
worldRotation = SpatialMathUtils.calculateRotationFromPointToPoint(previousWorldPos,worldPosition).mul(new Quaterniond(0,0.707,0,0.707));
}
//create new capsule
length = previousWorldPos.distance(worldPosition) / 2.0;
if(length > 5000 || Double.isNaN(length) || Double.isInfinite(length) || length < 0){
if(length < 0){
LoggerInterface.loggerEngine.WARNING("Length is too short! " + length);
}
if(length > 5000){
LoggerInterface.loggerEngine.WARNING("Length is too long! " + length);
}
if(Double.isNaN(length) || Double.isInfinite(length)){
LoggerInterface.loggerEngine.WARNING("Length is invalid number! " + length);
}
if(Double.isNaN(previousWorldPos.x) || Double.isInfinite(previousWorldPos.x)){
LoggerInterface.loggerEngine.WARNING("Previous hitbox position isn't valid!");
}
if(Double.isNaN(worldPosition.x) || Double.isInfinite(worldPosition.x)){
LoggerInterface.loggerEngine.WARNING("Current hitbox position isn't valid!");
}
length = 0.1;
}
geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), hitboxState.getHitboxData().getRadius(), length, Collidable.TYPE_OBJECT_BIT);
CollisionBodyCreation.attachGeomToBody(collisionEngine,body,geom);
PhysicsEntityUtils.setGeometryPosition(collisionEngine, geom, bodyPosition, worldRotation);
} else {
//called first time the hitbox updates position
this.destroyGeom(collisionEngine, geom);
//create new capsule
geom = CollisionBodyCreation.createCapsuleShape(manager.getCollisionEngine(), hitboxState.getHitboxData().getRadius(), length, Collidable.TYPE_OBJECT_BIT);
CollisionBodyCreation.attachGeomToBody(collisionEngine,body,geom);
}
//update maps and other variables for next frame
this.registerGeom(geom, hitboxState);
hitboxState.setPreviousWorldPos(worldPosition);
}
/**
* 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 HitboxState getShapeStatus(DGeom geom){
return this.geomStateMap.get(geom);
}
/**
* Gets the geom from the state object
* @param state The state object
* @return The associated geom
*/
public DGeom getGeom(HitboxState state){
return this.stateGeomMap.get(state);
}
/**
* Gets the hitbox state of the entity
* @param entity the entity
* @return the hitbox state if it exists
*/
public static HitboxCollectionState getHitboxState(Entity entity){
return (HitboxCollectionState)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
* @param isServer true if this is the server, false otherwise
* @return The hitbox state if it exists, null otherwise
*/
public static HitboxCollectionState destroyHitboxState(Entity entity, boolean isServer){
HitboxCollectionState state = null;
if(HitboxCollectionState.hasHitboxState(entity)){
state = HitboxCollectionState.getHitboxState(entity);
state.manager.deregisterHitbox(state);
state.destroy(isServer);
}
return state;
}
/**
* Destroys the content of the state
* @param true if this is the server, false otherwise
*/
protected void destroy(boolean isServer){
CollisionEngine engine = null;
if(isServer){
Realm realm = Globals.realmManager.getEntityRealm(parent);
if(realm != null){
engine = realm.getHitboxManager().getCollisionEngine();
}
} else {
engine = Globals.clientSceneWrapper.getHitboxManager().getCollisionEngine();
}
if(engine != null){
PhysicsUtils.destroyBody(engine, body);
}
}
/**
* 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;
for(DGeom geom : this.geoms){
HitboxState shapeState = this.getShapeStatus(geom);
shapeState.setActive(state);
}
}
/**
* Gets the block override status
* @return true if should override hitboxes with blockboxes, false otherwise
*/
public boolean isBlockOverride(){
return this.blockOverride;
}
/**
* Sets the block override of the hitbox
* @param state true to override attack hitboxes with block boxes, false otherwise
*/
public void setBlockOverride(boolean state){
this.blockOverride = state;
for(DGeom geom : this.geoms){
HitboxState shapeState = this.getShapeStatus(geom);
shapeState.setBlockOverride(state);
}
}
/**
* Gets the list of all DGeoms in the data
* @return the list of all DGeoms
*/
public List<DGeom> getGeometries(){
return this.geoms;
}
/**
* Gets the list of all hitboxes
* @return The list of all hitboxes
*/
public List<HitboxState> getHitboxes(){
return this.allStates;
}
/**
* Gets the hitboxes associated with a bone
* @param bone The bone
* @return The list of hitboxes if at least one is present, null otherwise
*/
private List<HitboxState> getHitboxes(String bone){
return this.boneHitboxMap.get(bone);
}
/**
* Adds a hitbox to a bone
* @param bone The bone
* @param state The hitbox
*/
private void addHitbox(String bone, HitboxState state){
if(this.boneHitboxMap.containsKey(bone)){
this.boneHitboxMap.get(bone).add(state);
} else {
List<HitboxState> states = new LinkedList<HitboxState>();
states.add(state);
this.boneHitboxMap.put(bone,states);
}
this.allStates.add(state);
}
/**
* Adds a hitbox with an offset
* @param state The hitbox
*/
private void addHitbox(HitboxState state){
this.nonBoneHitboxes.add(state);
this.allStates.add(state);
}
/**
* Registers a geometry
* @param geom The geom
* @param state The state associated with the geom
*/
private void registerGeom(DGeom geom, HitboxState state){
if(state == null){
throw new IllegalArgumentException("Null hitbox state provided to geometry register!");
}
this.geoms.add(geom);
this.geomStateMap.put(geom,state);
this.stateGeomMap.put(state,geom);
}
/**
* Destroys a geometry
* @param collisionEngine The collision engine for the body
* @param geom The geometry
*/
private void destroyGeom(CollisionEngine collisionEngine, DGeom geom){
HitboxState state = this.geomStateMap.remove(geom);
this.stateGeomMap.remove(state);
this.geoms.remove(geom);
CollisionBodyCreation.destroyShape(collisionEngine, geom);
}
/**
* Gets the hitbox type of a given hitbox data
* @param data The data
* @return The type of hitbox
*/
private static HitboxType getType(HitboxData data){
switch(data.getType()){
case HitboxData.HITBOX_TYPE_HIT: {
return HitboxType.HIT;
}
case HitboxData.HITBOX_TYPE_HURT: {
return HitboxType.HURT;
}
case HitboxData.HITBOX_TYPE_HIT_CONNECTED: {
return HitboxType.HIT;
}
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
return HitboxType.HURT;
}
case HitboxData.HITBOX_TYPE_STATIC_CAPSULE: {
return HitboxType.HURT;
}
default: {
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Trying to parse undefined hitbox type " + data.getType()));
return HitboxType.HIT;
}
}
}
/**
* Gets the shape type of a hitbox data object
* @param data The data
* @return The shape type
*/
private static HitboxShapeType getShapeType(HitboxData data){
switch(data.getType()){
case HitboxData.HITBOX_TYPE_HIT:
case HitboxData.HITBOX_TYPE_HURT: {
return HitboxShapeType.SPHERE;
}
case HitboxData.HITBOX_TYPE_HIT_CONNECTED:
case HitboxData.HITBOX_TYPE_HURT_CONNECTED: {
return HitboxShapeType.CAPSULE;
}
case HitboxData.HITBOX_TYPE_STATIC_CAPSULE: {
return HitboxShapeType.STATIC_CAPSULE;
}
default: {
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Trying to parse undefined hitbox shape type " + data.getType()));
return HitboxShapeType.SPHERE;
}
}
}
/**
* Gets the hitbox subtype
* @param data The data
* @return The subtype
*/
private static HitboxSubtype getSubType(HitboxData data){
switch(data.getSubType()){
case HitboxData.HITBOX_SUBTYPE_SWEET: {
return HitboxSubtype.SWEET;
}
case HitboxData.HITBOX_SUBTYPE_REUGLAR: {
return HitboxSubtype.REGULAR;
}
case HitboxData.HITBOX_SUBTYPE_SOUR: {
return HitboxSubtype.SOUR;
}
default: {
LoggerInterface.loggerEngine.ERROR(new IllegalArgumentException("Trying to parse undefined hitbox subtype " + data.getSubType()));
return HitboxSubtype.REGULAR;
}
}
}
/**
* The status of a single shape inside the overall hitbox data
* IE a single sphere on the overall body
*/
public static class HitboxState {
/**
* Types of geometry that can be used as individual shapes within a hitbox
*/
public enum HitboxShapeType {
//this is a true sphere. It will teleport every frame to its new position
SPHERE,
//for this one, the shape is a capsule in the collision engine, however
//the capsule is used to have continuity between the last position the hitbox occupied and the current one
CAPSULE,
//this is a true static capsule, it doesn't act as two connected spheres but is instead a capsule that teleports between frames
STATIC_CAPSULE,
}
//the name of the bone the hitbox is attached to
String boneName;
//the type of hitbox
HitboxType type;
//the subtype
HitboxSubtype subType;
//the type of geometry
HitboxShapeType shapeType;
//controls whether the hitbox is active
boolean isActive;
//controls whether the block override is active or not
//if it is active, hitboxes should behave like block boxes
boolean blockOverride = false;
//the previous position of this hitbox shape
Vector3d previousWorldPos = null;
//if true, just had a collision
boolean hadCollision = false;
//the data of the hitbox
HitboxData data;
/**
* Creates a status object for a hitbox
* @param boneName The name of the bone the hitbox is attached to, if any
* @param data the hitbox data object
* @param type The type of hitbox
* @param subType The subtype of hitbox
* @param shapeType The type of shape the hitbox is
* @param isActive if the hitbox is active or not
*/
public HitboxState(String boneName, HitboxData data, HitboxType type, HitboxSubtype subType, HitboxShapeType shapeType, boolean isActive){
this.boneName = boneName;
this.data = data;
this.type = type;
this.subType = subType;
this.shapeType = shapeType;
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 hitbox data for this shape
* @return The data
*/
public HitboxData getHitboxData(){
return this.data;
}
/**
* Sets the hitbox data for this shape
* @param data The data
*/
public void setHitboxData(HitboxData data){
this.data = data;
}
/**
* 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 the subtype of the hitbox
* @return The subtype
*/
public HitboxSubtype getSubType(){
return subType;
}
/**
* Sets the subtype of the hitbox
* @param subType The subtype
*/
public void setSubType(HitboxSubtype subType){
this.subType = subType;
}
/**
* 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;
}
/**
* Gets whether the block override is active or not
* @return true if the block override is active, false otherwise
*/
public boolean isBlockOverride(){
return blockOverride;
}
/**
* Sets whether the block override is active or not
* @param blockOverride true if the block override is active, false otherwise
*/
public void setBlockOverride(boolean blockOverride){
this.blockOverride = blockOverride;
}
/**
* Gets the previous world position of this hitbox
* @return The previous world position
*/
public Vector3d getPreviousWorldPos(){
return this.previousWorldPos;
}
/**
* sets the previous world position of this hitbox shape
* @param previousWorldPos The previous world position
*/
public void setPreviousWorldPos(Vector3d previousWorldPos){
this.previousWorldPos = previousWorldPos;
}
/**
* Sets the status of whether this hitbox just had a collision or not
* @param hadCollision true if had a collision, false otherwise
*/
public void setHadCollision(boolean hadCollision){
this.hadCollision = hadCollision;
}
/**
* Gets the collision status of the hitbox
* @return true if had a collision, false otherwise
*/
public boolean getHadCollision(){
return this.hadCollision;
}
}
}