Renderer/src/main/java/electrosphere/entity/state/collidable/ServerCollidableTree.java
2025-06-04 16:48:37 -04:00

209 lines
8.3 KiB
Java

package electrosphere.entity.state.collidable;
import electrosphere.collision.collidable.Collidable;
import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.btree.BehaviorTree;
import electrosphere.entity.state.gravity.ServerGravityTree;
import electrosphere.entity.state.movement.fall.ServerFallTree;
import org.ode4j.ode.DBody;
import org.ode4j.ode.DGeom;
/**
* Server collidable tree
*/
public class ServerCollidableTree implements BehaviorTree {
/**
* The parent of the collidable
*/
private Entity parent;
/**
* The body
*/
protected DBody body;
/**
* The collidable
*/
private Collidable collidable;
/**
* Constructor
* @param e The entity
* @param collidable The collidable
* @param body The body
*/
public ServerCollidableTree(Entity e, Collidable collidable, DBody body){
parent = e;
this.collidable = collidable;
this.body = body;
}
/**
* Constructor
* @param e The entity
* @param collidable The collidable
* @param geom The Geom
*/
public ServerCollidableTree(Entity e, Collidable collidable, DGeom geom){
parent = e;
this.collidable = collidable;
}
/**
* Simulates the collidable tree
* @param deltaTime The amount of time to simulate by
*/
public void simulate(float deltaTime){
//have we hit a terrain impulse?
//handle impulses
for(Impulse impulse : collidable.getImpulses()){
if(impulse.type.matches(Collidable.TYPE_CREATURE)){
if(ServerGravityTree.getServerGravityTree(parent)!=null){
ServerGravityTree.getServerGravityTree(parent).start();
}
}
if(impulse.type.matches(Collidable.TYPE_WORLD_BOUND) || impulse.type.matches(Collidable.TYPE_STATIC)){
this.resetGravityFall();
}
}
collidable.setReady(true);
//capsule-specific block collision logic
// if(body.isEnabled() && body.getFirstGeom() != null && (body.getFirstGeom() instanceof DCapsule)){
// Realm realm = Globals.serverState.realmManager.getEntityRealm(parent);
// if(realm.getDataCellManager() instanceof VoxelCellManager){
// VoxelCellManager voxelCellManager = (VoxelCellManager)realm.getDataCellManager();
// //get capsule params
// DCapsule capsuleGeom = (DCapsule)body.getFirstGeom();
// double length = capsuleGeom.getLength();
// double halfLength = length / 2.0;
// double radius = capsuleGeom.getRadius();
// Vector3d bodyOffset = PhysicsUtils.odeVecToJomlVec(body.getFirstGeom().getOffsetPosition());
// //entity spatial transforms
// Vector3d entRealPos = EntityUtils.getPosition(parent);
// Quaterniond entRot = EntityUtils.getRotation(parent);
// //start and end of capsule
// Vector3d realStart = new Vector3d(0,-halfLength,0).rotate(entRot).add(entRealPos).add(bodyOffset);
// Vector3d realEnd = new Vector3d(0,halfLength,0).rotate(entRot).add(entRealPos).add(bodyOffset);
// //block position of body
// Vector3d blockPos = ServerWorldData.clampRealToBlock(entRealPos);
// Vector3d currBlockPos = new Vector3d();
// //get dims to scan along (ceil to overcompensate -- better to over scan than underscan)
// int halfRadBlockLen = (int)Math.ceil(halfLength / BlockChunkData.BLOCK_SIZE_MULTIPLIER);
// int radBlockLen = (int)Math.ceil(radius / BlockChunkData.BLOCK_SIZE_MULTIPLIER);
// //final corrected position
// Vector3d corrected = new Vector3d(entRealPos);
// //scan for all potential blocks
// for(int x = -radBlockLen; x <= radBlockLen; x++){
// for(int z = -radBlockLen; z <= radBlockLen; z++){
// for(int y = -halfRadBlockLen; y <= halfRadBlockLen; y++){
// currBlockPos.set(blockPos).add(
// x * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
// y * BlockChunkData.BLOCK_SIZE_MULTIPLIER,
// z * BlockChunkData.BLOCK_SIZE_MULTIPLIER
// );
// Vector3i chunkPos = ServerWorldData.convertRealToChunkSpace(currBlockPos);
// Vector3i entBlockPos = ServerWorldData.convertRealToLocalBlockSpace(currBlockPos);
// //error check bounds
// if(chunkPos.x < 0 || chunkPos.y < 0 || chunkPos.z < 0){
// continue;
// }
// //get block data for block to check
// BlockChunkData data = voxelCellManager.getBlocksAtPosition(chunkPos);
// short type = data.getType(entBlockPos.x, entBlockPos.y, entBlockPos.z);
// if(type != BlockChunkData.BLOCK_TYPE_EMPTY){
// //AABB for the voxel
// AABBd voxelBox = new AABBd(
// currBlockPos.x,
// currBlockPos.y,
// currBlockPos.z,
// currBlockPos.x + BlockChunkData.BLOCK_SIZE_MULTIPLIER,
// currBlockPos.y + BlockChunkData.BLOCK_SIZE_MULTIPLIER,
// currBlockPos.z + BlockChunkData.BLOCK_SIZE_MULTIPLIER
// );
// //actually collision check
// CollisionResult collisionResult = CollisionUtils.collideCapsuleAABB(realStart, realEnd, radius, voxelBox);
// if(collisionResult != null){
// double pen = collisionResult.getPenetration();
// double forceMul = pen * 0.3;
// Vector3d normal = collisionResult.getNormal().mul(forceMul);
// if(normal != null){
// // body.addForce(normal.x, normal.y, normal.z);
// //correct the position of the capsule
// corrected.add(normal);
// }
// }
// }
// }
// }
// }
// //apply correction
// CollisionObjUtils.serverPositionCharacter(parent, corrected);
// }
// }
}
/**
* Sets the structures backing this collidable tree
* @param body The ode body
* @param collidable The collidable
*/
public void setCollisionObject(DBody body, Collidable collidable){
this.body = body;
this.collidable = collidable;
}
/**
* Checks if the entity has a server collidable tree
* @param e The entity
* @return true if it has a collidable tree, false otherwise
*/
public static boolean hasServerCollidableTree(Entity e){
return e.containsKey(EntityDataStrings.SERVER_COLLIDABLE_TREE);
}
/**
* Gets the server collidable tree on an entity
* @param e The entity
* @return The tree if it exists, false otherwise
*/
public static ServerCollidableTree getServerCollidableTree(Entity e){
return (ServerCollidableTree)e.getData(EntityDataStrings.SERVER_COLLIDABLE_TREE);
}
/**
* Adds a terrain collision to the collidable list
*/
protected void resetGravityFall(){
if(ServerGravityTree.getServerGravityTree(parent)!=null){
ServerGravityTree.getServerGravityTree(parent).stop();
}
if(ServerFallTree.getFallTree(parent)!=null){
ServerFallTree.getFallTree(parent).land();
}
}
}