interaction target work
Some checks failed
studiorailgun/Renderer/pipeline/head There was a failure building this commit

This commit is contained in:
austin 2025-04-26 15:58:29 -04:00
parent 589833b32f
commit 75fe5a9d1a
7 changed files with 115 additions and 12 deletions

View File

@ -1547,6 +1547,7 @@ Fab selection tool actually loads fab files
Fix fab file reading Fix fab file reading
Fab tool can show transparent, loaded version of fab file Fab tool can show transparent, loaded version of fab file
Interaction target tooltip at top of window Interaction target tooltip at top of window
Interaction target tooltip shows entity target, voxel targets

View File

@ -7,9 +7,12 @@ import java.util.concurrent.locks.ReentrantLock;
import org.joml.Matrix4d; import org.joml.Matrix4d;
import org.joml.Quaterniond; import org.joml.Quaterniond;
import org.joml.Vector3d; import org.joml.Vector3d;
import org.joml.Vector3i;
import org.ode4j.ode.DBody; import org.ode4j.ode.DBody;
import electrosphere.client.block.BlockChunkData;
import electrosphere.client.entity.camera.CameraEntityUtils; import electrosphere.client.entity.camera.CameraEntityUtils;
import electrosphere.client.terrain.cache.ChunkData;
import electrosphere.client.ui.menu.ingame.InteractionTargetMenu; import electrosphere.client.ui.menu.ingame.InteractionTargetMenu;
import electrosphere.collision.CollisionBodyCreation; import electrosphere.collision.CollisionBodyCreation;
import electrosphere.collision.CollisionEngine; import electrosphere.collision.CollisionEngine;
@ -19,8 +22,10 @@ import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.EntityTypes.EntityType;
import electrosphere.entity.types.common.CommonEntityUtils; import electrosphere.entity.types.common.CommonEntityUtils;
import electrosphere.game.data.collidable.CollidableTemplate; import electrosphere.game.data.collidable.CollidableTemplate;
import electrosphere.server.physics.terrain.manager.ServerTerrainChunk;
/** /**
* Manages the interaction state * Manages the interaction state
@ -220,14 +225,68 @@ public class ClientInteractionEngine {
if(Globals.playerEntity != null && Globals.playerCamera != null){ if(Globals.playerEntity != null && Globals.playerCamera != null){
boolean set = false; boolean set = false;
Entity camera = Globals.playerCamera; Entity camera = Globals.playerCamera;
Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera)).mul(-1.0); Vector3d eyePos = new Vector3d(CameraEntityUtils.getCameraEye(camera));
Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera)); Vector3d centerPos = new Vector3d(CameraEntityUtils.getCameraCenter(camera));
Entity target = ClientInteractionEngine.rayCast(centerPos, eyePos); Entity target = ClientInteractionEngine.rayCast(centerPos, new Vector3d(eyePos).mul(-1));
if(target != null){ if(target != null){
String text = CommonEntityUtils.getEntitySubtype(target); String text = CommonEntityUtils.getEntitySubtype(target);
InteractionTargetMenu.setInteractionTargetString(text); InteractionTargetMenu.setInteractionTargetString(text);
set = true; set = true;
} }
if(!set){
target = Globals.clientSceneWrapper.getCollisionEngine().rayCast(new Vector3d(centerPos), new Vector3d(eyePos).mul(-1), CollisionEngine.DEFAULT_INTERACT_DISTANCE);
if(target != null){
EntityType type = CommonEntityUtils.getEntityType(target);
if(type == null){
throw new Error("Entity does not have a type defined!");
}
switch(type){
case CREATURE: {
InteractionTargetMenu.setInteractionTargetString(CommonEntityUtils.getEntitySubtype(target));
set = true;
} break;
case ITEM: {
InteractionTargetMenu.setInteractionTargetString(CommonEntityUtils.getEntitySubtype(target));
set = true;
} break;
case FOLIAGE: {
InteractionTargetMenu.setInteractionTargetString(CommonEntityUtils.getEntitySubtype(target));
set = true;
} break;
default: {
//silently ignore
} break;
}
}
}
if(!set){
Vector3d collisionPosition = Globals.clientSceneWrapper.getCollisionEngine().rayCastPosition(centerPos, new Vector3d(eyePos).mul(-1), CollisionEngine.DEFAULT_INTERACT_DISTANCE);
if(collisionPosition != null && collisionPosition.distance(centerPos) < CollisionEngine.DEFAULT_INTERACT_DISTANCE){
//grab block at point
BlockChunkData blockChunkData = Globals.clientBlockManager.getChunkDataAtWorldPoint(Globals.clientWorldData.convertRealToWorldSpace(collisionPosition), 0);
if(blockChunkData != null){
Vector3i blockPos = Globals.clientWorldData.convertRealToBlockSpace(collisionPosition);
if(!blockChunkData.isEmpty(blockPos.x, blockPos.y, blockPos.z)){
short type = blockChunkData.getType(blockPos.x, blockPos.y, blockPos.z);
String text = Globals.gameConfigCurrent.getBlockData().getTypeFromId(type).getName();
InteractionTargetMenu.setInteractionTargetString(text);
set = true;
}
}
//if we didn't find a block type, try terrain
if(!set){
ChunkData chunkData = Globals.clientTerrainManager.getChunkDataAtWorldPoint(Globals.clientWorldData.convertRealToWorldSpace(collisionPosition), 0);
if(chunkData != null){
int voxelType = chunkData.getType(Globals.clientWorldData.convertRealToVoxelSpace(collisionPosition));
if(voxelType != ServerTerrainChunk.VOXEL_TYPE_AIR){
String text = Globals.gameConfigCurrent.getVoxelData().getTypeFromId(voxelType).getName();
InteractionTargetMenu.setInteractionTargetString(text);
set = true;
}
}
}
}
}
if(!set){ if(!set){
InteractionTargetMenu.setInteractionTargetString(""); InteractionTargetMenu.setInteractionTargetString("");
} }

View File

@ -68,7 +68,9 @@ public class ClientTerrainManager {
*/ */
static final int CACHE_SIZE_IN_MB = (CACHE_SIZE * ServerTerrainChunk.CHUNK_DIMENSION * ServerTerrainChunk.CHUNK_DIMENSION * ServerTerrainChunk.CHUNK_DIMENSION * 2 * 4) / 1024 / 1024; static final int CACHE_SIZE_IN_MB = (CACHE_SIZE * ServerTerrainChunk.CHUNK_DIMENSION * ServerTerrainChunk.CHUNK_DIMENSION * ServerTerrainChunk.CHUNK_DIMENSION * 2 * 4) / 1024 / 1024;
//used for caching the macro values /**
* used for caching the macro values
*/
ClientTerrainCache terrainCache; ClientTerrainCache terrainCache;
/** /**
@ -76,10 +78,14 @@ public class ClientTerrainManager {
*/ */
BlockChunkCache blockCache; BlockChunkCache blockCache;
//The world data for the client /**
* The world data for the client
*/
ClientWorldData clientWorldData; ClientWorldData clientWorldData;
//The queue of terrain chunk data to be buffered to gpu /**
* The queue of terrain chunk data to be buffered to gpu
*/
static List<TerrainChunkGenQueueItem> terrainChunkGenerationQueue = new LinkedList<TerrainChunkGenQueueItem>(); static List<TerrainChunkGenQueueItem> terrainChunkGenerationQueue = new LinkedList<TerrainChunkGenQueueItem>();
/** /**

View File

@ -634,7 +634,7 @@ public class CollisionEngine {
* @return The entity that the ray collides with if successful, null otherwise * @return The entity that the ray collides with if successful, null otherwise
*/ */
public Entity rayCast(Vector3d start, Vector3d direction, double length){ public Entity rayCast(Vector3d start, Vector3d direction, double length){
return rayCast(start,direction,length,null); return this.rayCast(start,direction,length,null);
} }
/** /**

View File

@ -18,6 +18,7 @@ import org.ode4j.ode.OdeHelper;
import electrosphere.collision.collidable.Collidable; import electrosphere.collision.collidable.Collidable;
import electrosphere.engine.Globals; import electrosphere.engine.Globals;
import electrosphere.entity.Entity; import electrosphere.entity.Entity;
import electrosphere.entity.state.attach.AttachUtils;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
public class RayCastCallback implements DNearCallback { public class RayCastCallback implements DNearCallback {
@ -79,6 +80,13 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) {
if(collidable2 != null && collidable2.getParent() == Globals.playerEntity){ if(collidable2 != null && collidable2.getParent() == Globals.playerEntity){
return; return;
} }
//don't collide with entities that are attached to the parent either
if(collidable1 != null && AttachUtils.getParent(collidable1.getParent()) != null && AttachUtils.getParent(collidable1.getParent()) == Globals.playerEntity){
return;
}
if(collidable2 != null && AttachUtils.getParent(collidable2.getParent()) != null && AttachUtils.getParent(collidable2.getParent()) == Globals.playerEntity){
return;
}
Globals.profiler.beginAggregateCpuSample("RayCastCallback - try collisions"); Globals.profiler.beginAggregateCpuSample("RayCastCallback - try collisions");
if( if(
@ -137,14 +145,27 @@ void RayCallback(void *Data, dGeomID Geometry1, dGeomID Geometry2) {
* Data object that contains the information for a ray cast check * Data object that contains the information for a ray cast check
*/ */
static class RayCastCallbackData { static class RayCastCallbackData {
//The map of ode DBody -> collidable
/**
* The map of ode DBody -> collidable
*/
Map<DBody,Collidable> bodyEntityMap; Map<DBody,Collidable> bodyEntityMap;
//The mask of collidable types to filter collisions by. Can be null.
/**
* The mask of collidable types to filter collisions by. Can be null.
*/
List<String> collidableTypeMask; List<String> collidableTypeMask;
//The entity that the ray cast collided with. If null, no entity was collided with.
/**
* The entity that the ray cast collided with. If null, no entity was collided with.
*/
Entity collidedEntity = null; Entity collidedEntity = null;
//The position in world space that the collision happened
/**
* The position in world space that the collision happened
*/
Vector3d collisionPosition = null; Vector3d collisionPosition = null;
/** /**
* Constructor * Constructor
* @param bodyEntityMap The map of ode DBody -> collidable * @param bodyEntityMap The map of ode DBody -> collidable

View File

@ -26,7 +26,11 @@ public class EntityTypes {
/** /**
* A piece of foliage * A piece of foliage
*/ */
FOLIAGE(3) FOLIAGE(3),
/**
* Special engine-created entities (ie not defined in a json file)
*/
ENGINE(4),
; ;
/** /**
@ -38,7 +42,7 @@ public class EntityTypes {
* Constructor * Constructor
* @param newValue The value * @param newValue The value
*/ */
EntityType(final int newValue){ private EntityType(final int newValue){
value = newValue; value = newValue;
} }

View File

@ -22,7 +22,9 @@ import electrosphere.entity.Entity;
import electrosphere.entity.EntityCreationUtils; import electrosphere.entity.EntityCreationUtils;
import electrosphere.entity.EntityDataStrings; import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils; import electrosphere.entity.EntityUtils;
import electrosphere.entity.types.EntityTypes.EntityType;
import electrosphere.entity.types.collision.CollisionObjUtils; import electrosphere.entity.types.collision.CollisionObjUtils;
import electrosphere.entity.types.common.CommonEntityUtils;
import electrosphere.logger.LoggerInterface; import electrosphere.logger.LoggerInterface;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration; import electrosphere.renderer.meshgen.TransvoxelModelGeneration;
import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData; import electrosphere.renderer.meshgen.TransvoxelModelGeneration.TransvoxelChunkData;
@ -59,6 +61,7 @@ public class TerrainChunk {
Globals.profiler.beginAggregateCpuSample("TerrainChunk.clientCreateTerrainChunkEntity"); Globals.profiler.beginAggregateCpuSample("TerrainChunk.clientCreateTerrainChunkEntity");
Entity rVal = EntityCreationUtils.createClientSpatialEntity(); Entity rVal = EntityCreationUtils.createClientSpatialEntity();
CommonEntityUtils.setEntityType(rVal, EntityType.ENGINE);
if(hasPolygons && chunkData.terrainGrid != null && chunkData.textureGrid != null){ if(hasPolygons && chunkData.terrainGrid != null && chunkData.textureGrid != null){
generationService.submit(() -> { generationService.submit(() -> {
TerrainChunkData data; TerrainChunkData data;
@ -149,4 +152,13 @@ public class TerrainChunk {
generationService.shutdownNow(); generationService.shutdownNow();
} }
/**
* Checks if this is a terrain entity
* @param entity The entity
* @return True if it is a terrain entity, false otherwise
*/
public static boolean isTerrainEntity(Entity entity){
return entity.containsKey(EntityDataStrings.TERRAIN_IS_TERRAIN);
}
} }