use of org.terasology.engine.physics.HitResult in project Terasology by MovingBlocks.
the class BulletPhysics method rayTrace.
@Override
public HitResult rayTrace(Vector3f from, Vector3f direction, float distance, Set<EntityRef> excludedEntities, CollisionGroup... collisionGroups) {
if (excludedEntities == null || excludedEntities.size() == 0) {
return rayTrace(from, direction, distance, collisionGroups);
}
Vector3f to = new Vector3f(direction);
to.normalize();
to.mul(distance);
to.add(from);
short filter = combineGroups(collisionGroups);
// lookup all the collision item ids for these entities
Set<Integer> excludedCollisionIds = Sets.newHashSet();
for (EntityRef excludedEntity : excludedEntities) {
if (entityRigidBodies.containsKey(excludedEntity)) {
excludedCollisionIds.add(entityRigidBodies.get(excludedEntity).rb.getBroadphaseHandle().getUid());
}
if (entityColliders.containsKey(excludedEntity)) {
excludedCollisionIds.add(entityColliders.get(excludedEntity).collider.getBroadphaseHandle().getUid());
}
if (entityTriggers.containsKey(excludedEntity)) {
excludedCollisionIds.add(entityTriggers.get(excludedEntity).getBroadphaseHandle().getUid());
}
}
AllHitsRayResultCallback callback = new AllHitsRayResultCallback(from, to);
callback.setCollisionFilterGroup(StandardCollisionGroup.ALL.getFlag());
callback.setCollisionFilterMask(filter);
discreteDynamicsWorld.rayTest(from, to, callback);
if (callback.hasHit()) {
btCollisionObjectConstArray collisionObjects = callback.getCollisionObjects();
for (int x = 0; x < collisionObjects.size(); x++) {
btCollisionObject collisionObject = collisionObjects.atConst(x);
if (!excludedCollisionIds.contains(collisionObject.getBroadphaseHandle().getUid())) {
Vector3f hitPointWorld = callback.getHitPointWorld().at(x);
Vector3f hitNormalWorld = callback.getHitNormalWorld().at(x);
callback.dispose();
if (collisionObject.userData instanceof EntityRef) {
// we hit an other entity
return new HitResult((EntityRef) collisionObject.userData, hitPointWorld, hitNormalWorld);
} else if ((collisionObject.getCollisionFlags() & btCollisionObject.CollisionFlags.CF_VOXEL_OBJECT) > 0) {
btVector3i pos = new btVector3i();
collisionObject.getVoxelPosition(pos);
Vector3i voxelPosition = new Vector3i(pos.getX(), pos.getY(), pos.getZ());
final EntityRef entityAt = blockEntityRegistry.getEntityAt(voxelPosition);
return new HitResult(entityAt, hitPointWorld, hitNormalWorld, voxelPosition);
} else {
// we hit something we don't understand, assume its nothing and log a warning
logger.warn("Unidentified object was hit in the physics engine: {}", collisionObject.userData);
}
}
}
} else {
callback.dispose();
}
return new HitResult();
}
use of org.terasology.engine.physics.HitResult in project Terasology by MovingBlocks.
the class BulletPhysics method rayTrace.
@Override
public HitResult rayTrace(Vector3f from, Vector3f direction, float distance, CollisionGroup... collisionGroups) {
Vector3f to = new Vector3f(direction);
to.normalize();
to.mul(distance);
to.add(from);
short filter = combineGroups(collisionGroups);
ClosestRayResultCallback callback = new ClosestRayResultCallback(from, to);
callback.setCollisionFilterGroup(StandardCollisionGroup.ALL.getFlag());
callback.setCollisionFilterMask(filter);
discreteDynamicsWorld.rayTest(from, to, callback);
if (callback.hasHit()) {
btCollisionObject collisionObject = callback.getCollisionObject();
Vector3f hitPointWorld = new Vector3f();
callback.getHitPointWorld(hitPointWorld);
Vector3f hitNormalWorld = new Vector3f();
callback.getHitNormalWorld(hitNormalWorld);
if (callback.hasHit()) {
callback.dispose();
if (collisionObject.userData instanceof EntityRef) {
// we hit an other entity
return new HitResult((EntityRef) collisionObject.userData, hitPointWorld, hitNormalWorld);
} else if ((collisionObject.getCollisionFlags() & btCollisionObject.CollisionFlags.CF_VOXEL_OBJECT) > 0) {
btVector3i pos = new btVector3i();
collisionObject.getVoxelPosition(pos);
Vector3i voxelPosition = new Vector3i(pos.getX(), pos.getY(), pos.getZ());
final EntityRef entityAt = blockEntityRegistry.getEntityAt(voxelPosition);
return new HitResult(entityAt, hitPointWorld, hitNormalWorld, voxelPosition);
} else {
// we hit something we don't understand, assume its nothing and log a warning
logger.warn("Unidentified object was hit in the physics engine: {}", collisionObject.userData);
}
}
} else {
callback.dispose();
}
return new HitResult();
}
use of org.terasology.engine.physics.HitResult in project Terasology by MovingBlocks.
the class CharacterSystem method onAttackRequest.
@ReceiveEvent(components = LocationComponent.class, netFilter = RegisterMode.AUTHORITY)
public void onAttackRequest(AttackRequest event, EntityRef character, CharacterComponent characterComponent) {
// if an item is used, make sure this entity is allowed to attack with it
if (event.getItem().exists()) {
if (!character.equals(event.getItem().getOwner())) {
return;
}
}
OnItemUseEvent onItemUseEvent = new OnItemUseEvent();
character.send(onItemUseEvent);
if (!onItemUseEvent.isConsumed()) {
EntityRef gazeEntity = GazeAuthoritySystem.getGazeEntityForCharacter(character);
LocationComponent gazeLocation = gazeEntity.getComponent(LocationComponent.class);
Vector3f direction = gazeLocation.getWorldDirection(new Vector3f());
Vector3f originPos = gazeLocation.getWorldPosition(new Vector3f());
if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.RECORDING) {
directionAndOriginPosRecorderList.getAttackEventDirectionAndOriginPosRecorder().add(direction, originPos);
} else if (recordAndReplayCurrentStatus.getStatus() == RecordAndReplayStatus.REPLAYING) {
Vector3f[] data = directionAndOriginPosRecorderList.getAttackEventDirectionAndOriginPosRecorder().poll();
direction = data[0];
originPos = data[1];
}
HitResult result = physics.rayTrace(originPos, direction, characterComponent.interactionRange, Sets.newHashSet(character), DEFAULTPHYSICSFILTER);
if (result.isHit()) {
result.getEntity().send(new AttackEvent(character, event.getItem()));
}
}
}
use of org.terasology.engine.physics.HitResult in project Terasology by MovingBlocks.
the class CharacterSystem method isPredictionOfEventCorrect.
private boolean isPredictionOfEventCorrect(EntityRef character, ActivationRequest event) {
CharacterComponent characterComponent = character.getComponent(CharacterComponent.class);
EntityRef camera = GazeAuthoritySystem.getGazeEntityForCharacter(character);
LocationComponent location = camera.getComponent(LocationComponent.class);
Vector3f direction = location.getWorldDirection(new Vector3f());
if (!(event.getDirection().equals(direction, 0.0001f))) {
logger.error("Direction at client {} was different than direction at server {}", event.getDirection(), direction);
}
// Assume the exact same value in case there are rounding mistakes:
direction = event.getDirection();
Vector3f originPos = location.getWorldPosition(new Vector3f());
if (!(event.getOrigin().equals(originPos, 0.0001f))) {
String msg = "Player {} seems to have cheated: It stated that it performed an action from {} but the predicted position is {}";
logger.info(msg, getPlayerNameFromCharacter(character), event.getOrigin(), originPos);
return false;
}
if (event.isOwnedEntityUsage()) {
if (!event.getUsedOwnedEntity().exists()) {
String msg = "Denied activation attempt by {} since the used entity does not exist on the authority";
logger.info(msg, getPlayerNameFromCharacter(character));
return false;
}
if (!networkSystem.getOwnerEntity(event.getUsedOwnedEntity()).equals(networkSystem.getOwnerEntity(character))) {
String msg = "Denied activation attempt by {} since it does not own the entity at the authority";
logger.info(msg, getPlayerNameFromCharacter(character));
return false;
}
} else {
// check for cheats so that data can later be trusted:
if (event.getUsedOwnedEntity().exists()) {
String msg = "Denied activation attempt by {} since it is not properly marked as owned entity usage";
logger.info(msg, getPlayerNameFromCharacter(character));
return false;
}
}
if (event.isEventWithTarget()) {
if (!event.getTarget().exists()) {
String msg = "Denied activation attempt by {} since the target does not exist on the authority";
logger.info(msg, getPlayerNameFromCharacter(character));
// can happen if target existed on client
return false;
}
// FIXME This is the same code as in LocalPlayer#activateTargetOrOwnedEntity to derive the actual interaction range from the
// player's character component and the used item's range component...
float interactionRange;
if (event.isOwnedEntityUsage() && event.getUsedOwnedEntity().hasComponent(RangeComponent.class)) {
interactionRange = Math.max(event.getUsedOwnedEntity().getComponent(RangeComponent.class).range, characterComponent.interactionRange);
} else {
interactionRange = characterComponent.interactionRange;
}
HitResult result = physics.rayTrace(originPos, direction, interactionRange, Sets.newHashSet(character), DEFAULTPHYSICSFILTER);
if (!result.isHit()) {
String msg = "Denied activation attempt by {} since at the authority there was nothing to activate at that place";
logger.info(msg, getPlayerNameFromCharacter(character));
return false;
}
EntityRef hitEntity = result.getEntity();
if (!hitEntity.equals(event.getTarget())) {
/**
* Tip for debugging this issue: Obtain the network id of hit entity and search it in both client and
* server entity dump. When certain fields don't get replicated, then wrong entity might get hin in the
* hit test.
*/
String msg = "Denied activation attempt by {} since at the authority another entity would have been activated";
logger.info(msg, getPlayerNameFromCharacter(character));
return false;
}
if (!(event.getHitPosition().equals(result.getHitPoint(), 0.0001f))) {
String msg = "Denied activation attempt by {} since at the authority the object got hit at a differnt position";
logger.info(msg, getPlayerNameFromCharacter(character));
return false;
}
} else {
// In order to trust the data later we need to verify it even if it should be correct if no one cheats:
if (event.getTarget().exists()) {
String msg = "Denied activation attempt by {} since the event was not properly labeled as having a target";
logger.info(msg, getPlayerNameFromCharacter(character));
return false;
}
if (event.getHitPosition() != null) {
String msg = "Denied activation attempt by {} since the event was not properly labeled as having a hit position";
logger.info(msg, getPlayerNameFromCharacter(character));
return false;
}
if (event.getHitNormal() != null) {
String msg = "Denied activation attempt by {} since the event was not properly labeled as having a hit delta";
logger.info(msg, getPlayerNameFromCharacter(character));
return false;
}
}
return true;
}
use of org.terasology.engine.physics.HitResult in project Terasology by MovingBlocks.
the class PhysicsSystem method update.
@Override
public void update(float delta) {
PerformanceMonitor.startActivity("Physics Renderer");
physics.update(time.getGameDelta());
PerformanceMonitor.endActivity();
// Update the velocity from physics engine bodies to Components:
Iterator<EntityRef> iter = physics.physicsEntitiesIterator();
while (iter.hasNext()) {
EntityRef entity = iter.next();
RigidBodyComponent comp = entity.getComponent(RigidBodyComponent.class);
RigidBody body = physics.getRigidBody(entity);
// force location component to update and sync trigger state
if (entity.hasComponent(TriggerComponent.class)) {
physics.updateTrigger(entity);
}
if (body.isActive()) {
body.getLinearVelocity(comp.velocity);
body.getAngularVelocity(comp.angularVelocity);
Vector3f vLocation = body.getLocation(new Vector3f());
Vector3f vDirection = new Vector3f(comp.velocity);
float fDistanceThisFrame = vDirection.length();
vDirection.normalize();
fDistanceThisFrame = fDistanceThisFrame * delta;
while (true) {
HitResult hitInfo = physics.rayTrace(vLocation, vDirection, fDistanceThisFrame + 0.5f, DEFAULT_COLLISION_GROUP);
if (hitInfo.isHit()) {
Block hitBlock = worldProvider.getBlock(hitInfo.getBlockPosition());
if (hitBlock != null) {
Vector3f vTravelledDistance = vLocation.sub(hitInfo.getHitPoint());
float fTravelledDistance = vTravelledDistance.length();
if (fTravelledDistance > fDistanceThisFrame) {
break;
}
if (hitBlock.isPenetrable()) {
if (!hitInfo.getEntity().hasComponent(BlockComponent.class)) {
entity.send(new EntityImpactEvent(hitInfo.getHitPoint(), hitInfo.getHitNormal(), comp.velocity, fDistanceThisFrame, hitInfo.getEntity()));
break;
}
// decrease the remaining distance to check if we hit a block
fDistanceThisFrame = fDistanceThisFrame - fTravelledDistance;
vLocation = hitInfo.getHitPoint();
} else {
entity.send(new BlockImpactEvent(hitInfo.getHitPoint(), hitInfo.getHitNormal(), comp.velocity, fDistanceThisFrame, hitInfo.getEntity()));
break;
}
} else {
break;
}
} else {
break;
}
}
}
}
if (networkSystem.getMode().isServer() && time.getGameTimeInMs() - TIME_BETWEEN_NETSYNCS > lastNetsync) {
sendSyncMessages();
lastNetsync = time.getGameTimeInMs();
}
List<CollisionPair> collisionPairs = physics.getCollisionPairs();
for (CollisionPair pair : collisionPairs) {
if (pair.b.exists()) {
short bCollisionGroup = getCollisionGroupFlag(pair.b);
short aCollidesWith = getCollidesWithGroupFlag(pair.a);
if ((bCollisionGroup & aCollidesWith) != 0 || (pair.b.hasComponent(BlockComponent.class) && !pair.a.hasComponent(BlockComponent.class))) {
pair.a.send(new CollideEvent(pair.b, pair.pointA, pair.pointB, pair.distance, pair.normal));
}
}
if (pair.a.exists()) {
short aCollisionGroup = getCollisionGroupFlag(pair.a);
short bCollidesWith = getCollidesWithGroupFlag(pair.b);
if ((aCollisionGroup & bCollidesWith) != 0 || (pair.a.hasComponent(BlockComponent.class) && !pair.b.hasComponent(BlockComponent.class))) {
pair.b.send(new CollideEvent(pair.a, pair.pointB, pair.pointA, pair.distance, new Vector3f(pair.normal).mul(-1.0f)));
}
}
}
}
Aggregations