Search in sources :

Example 1 with 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, 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();
}
Also used : HitResult(org.terasology.engine.physics.HitResult) com.badlogic.gdx.physics.bullet.collision.btCollisionObjectConstArray(com.badlogic.gdx.physics.bullet.collision.btCollisionObjectConstArray) Vector3f(org.joml.Vector3f) Vector3i(org.joml.Vector3i) com.badlogic.gdx.physics.bullet.collision.btVector3i(com.badlogic.gdx.physics.bullet.collision.btVector3i) com.badlogic.gdx.physics.bullet.collision.btVector3i(com.badlogic.gdx.physics.bullet.collision.btVector3i) EntityRef(org.terasology.engine.entitySystem.entity.EntityRef) AllHitsRayResultCallback(com.badlogic.gdx.physics.bullet.collision.AllHitsRayResultCallback) com.badlogic.gdx.physics.bullet.collision.btManifoldPoint(com.badlogic.gdx.physics.bullet.collision.btManifoldPoint) com.badlogic.gdx.physics.bullet.collision.btCollisionObject(com.badlogic.gdx.physics.bullet.collision.btCollisionObject)

Example 2 with 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();
}
Also used : HitResult(org.terasology.engine.physics.HitResult) Vector3f(org.joml.Vector3f) Vector3i(org.joml.Vector3i) com.badlogic.gdx.physics.bullet.collision.btVector3i(com.badlogic.gdx.physics.bullet.collision.btVector3i) com.badlogic.gdx.physics.bullet.collision.btVector3i(com.badlogic.gdx.physics.bullet.collision.btVector3i) EntityRef(org.terasology.engine.entitySystem.entity.EntityRef) com.badlogic.gdx.physics.bullet.collision.btCollisionObject(com.badlogic.gdx.physics.bullet.collision.btCollisionObject) ClosestRayResultCallback(com.badlogic.gdx.physics.bullet.collision.ClosestRayResultCallback)

Example 3 with 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()));
        }
    }
}
Also used : HitResult(org.terasology.engine.physics.HitResult) OnItemUseEvent(org.terasology.engine.logic.characters.events.OnItemUseEvent) Vector3f(org.joml.Vector3f) EntityRef(org.terasology.engine.entitySystem.entity.EntityRef) LocationComponent(org.terasology.engine.logic.location.LocationComponent) AttackEvent(org.terasology.engine.logic.characters.events.AttackEvent) ReceiveEvent(org.terasology.engine.entitySystem.event.ReceiveEvent)

Example 4 with HitResult

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;
}
Also used : HitResult(org.terasology.engine.physics.HitResult) RangeComponent(org.terasology.engine.logic.common.RangeComponent) Vector3f(org.joml.Vector3f) PlayerCharacterComponent(org.terasology.engine.logic.players.PlayerCharacterComponent) EntityRef(org.terasology.engine.entitySystem.entity.EntityRef) LocationComponent(org.terasology.engine.logic.location.LocationComponent)

Example 5 with HitResult

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)));
            }
        }
    }
}
Also used : RigidBodyComponent(org.terasology.engine.physics.components.RigidBodyComponent) HitResult(org.terasology.engine.physics.HitResult) BlockComponent(org.terasology.engine.world.block.BlockComponent) CollideEvent(org.terasology.engine.physics.events.CollideEvent) Vector3f(org.joml.Vector3f) BlockImpactEvent(org.terasology.engine.physics.events.BlockImpactEvent) OnChangedBlock(org.terasology.engine.world.OnChangedBlock) Block(org.terasology.engine.world.block.Block) EntityImpactEvent(org.terasology.engine.physics.events.EntityImpactEvent) EntityRef(org.terasology.engine.entitySystem.entity.EntityRef)

Aggregations

Vector3f (org.joml.Vector3f)9 HitResult (org.terasology.engine.physics.HitResult)9 EntityRef (org.terasology.engine.entitySystem.entity.EntityRef)8 Vector3i (org.joml.Vector3i)3 LocationComponent (org.terasology.engine.logic.location.LocationComponent)3 com.badlogic.gdx.physics.bullet.collision.btCollisionObject (com.badlogic.gdx.physics.bullet.collision.btCollisionObject)2 com.badlogic.gdx.physics.bullet.collision.btVector3i (com.badlogic.gdx.physics.bullet.collision.btVector3i)2 RangeComponent (org.terasology.engine.logic.common.RangeComponent)2 BlockComponent (org.terasology.engine.world.block.BlockComponent)2 AllHitsRayResultCallback (com.badlogic.gdx.physics.bullet.collision.AllHitsRayResultCallback)1 ClosestRayResultCallback (com.badlogic.gdx.physics.bullet.collision.ClosestRayResultCallback)1 com.badlogic.gdx.physics.bullet.collision.btCollisionObjectConstArray (com.badlogic.gdx.physics.bullet.collision.btCollisionObjectConstArray)1 com.badlogic.gdx.physics.bullet.collision.btManifoldPoint (com.badlogic.gdx.physics.bullet.collision.btManifoldPoint)1 ReceiveEvent (org.terasology.engine.entitySystem.event.ReceiveEvent)1 CharacterComponent (org.terasology.engine.logic.characters.CharacterComponent)1 ActivationPredicted (org.terasology.engine.logic.characters.events.ActivationPredicted)1 ActivationRequest (org.terasology.engine.logic.characters.events.ActivationRequest)1 AttackEvent (org.terasology.engine.logic.characters.events.AttackEvent)1 OnItemUseEvent (org.terasology.engine.logic.characters.events.OnItemUseEvent)1 PlayerCharacterComponent (org.terasology.engine.logic.players.PlayerCharacterComponent)1