Search in sources :

Example 1 with ShipTransform

use of org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.

the class EventsClient method onRenderTickEvent.

@SubscribeEvent
public void onRenderTickEvent(RenderTickEvent event) {
    final World world = Minecraft.getMinecraft().world;
    if (world == null) {
        // No ships to worry about.
        return;
    }
    double partialTicks = event.renderTickTime;
    if (Minecraft.getMinecraft().isGamePaused()) {
        partialTicks = Minecraft.getMinecraft().renderPartialTicksPaused;
    }
    if (event.phase == Phase.START) {
        lastPositionsMap.clear();
        for (PhysicsObject wrapper : ValkyrienUtils.getPhysosLoadedInWorld(world)) {
            wrapper.getShipTransformationManager().updateRenderTransform(partialTicks);
        }
        // variables so that Minecraft's interpolation code computes the correct value.
        for (final Entity entity : world.getLoadedEntityList()) {
            final EntityShipMovementData entityShipMovementData = ValkyrienUtils.getEntityShipMovementDataFor(entity);
            if (entityShipMovementData.getLastTouchedShip() != null && entityShipMovementData.getTicksSinceTouchedShip() < VSConfig.ticksToStickToShip) {
                final PhysicsObject shipPhysicsObject = ValkyrienUtils.getPhysObjWorld(world).getPhysObjectFromUUID(entityShipMovementData.getLastTouchedShip().getUuid());
                if (shipPhysicsObject == null) {
                    // This ship doesn't exist anymore, just remove it.
                    IDraggable.class.cast(entity).setEntityShipMovementData(entityShipMovementData.withLastTouchedShip(null));
                    continue;
                }
                final ShipTransform prevTickTransform = shipPhysicsObject.getPrevTickShipTransform();
                final ShipTransform shipRenderTransform = shipPhysicsObject.getShipTransformationManager().getRenderTransform();
                final Vector3dc entityAddedVelocity = entityShipMovementData.getAddedLinearVelocity();
                // The velocity the entity was moving without the added velocity from the ship
                final double entityMovementX = entity.posX - entityAddedVelocity.x() - entity.lastTickPosX;
                final double entityMovementY = entity.posY - entityAddedVelocity.y() - entity.lastTickPosY;
                final double entityMovementZ = entity.posZ - entityAddedVelocity.z() - entity.lastTickPosZ;
                // Compute the position the entity should be rendered at this frame
                final Vector3d entityShouldBeHere = new Vector3d(entity.lastTickPosX, entity.lastTickPosY, entity.lastTickPosZ);
                entityShouldBeHere.add(entityMovementX * partialTicks, entityMovementY * partialTicks, entityMovementZ * partialTicks);
                prevTickTransform.transformPosition(entityShouldBeHere, TransformType.GLOBAL_TO_SUBSPACE);
                shipRenderTransform.transformPosition(entityShouldBeHere, TransformType.SUBSPACE_TO_GLOBAL);
                // Save the entity lastTickPos in the map
                lastPositionsMap.put(entity, new Vector3d(entity.lastTickPosX, entity.lastTickPosY, entity.lastTickPosZ));
                // Then update lastTickPos such that Minecraft's interpolation code will render entity at entityShouldBeHere.
                entity.lastTickPosX = (entityShouldBeHere.x() - (entity.posX * partialTicks)) / (1 - partialTicks);
                entity.lastTickPosY = (entityShouldBeHere.y() - (entity.posY * partialTicks)) / (1 - partialTicks);
                entity.lastTickPosZ = (entityShouldBeHere.z() - (entity.posZ * partialTicks)) / (1 - partialTicks);
            }
        }
    // endregion
    } else {
        // Once the rendering code has finished we restore the lastTickPos variables to their old values.
        for (final Entity entity : world.getLoadedEntityList()) {
            if (lastPositionsMap.containsKey(entity)) {
                final Vector3dc entityLastPosition = lastPositionsMap.get(entity);
                entity.lastTickPosX = entityLastPosition.x();
                entity.lastTickPosY = entityLastPosition.y();
                entity.lastTickPosZ = entityLastPosition.z();
            }
        }
    }
}
Also used : EntityShipMovementData(org.valkyrienskies.mod.common.entity.EntityShipMovementData) Vector3dc(org.joml.Vector3dc) Entity(net.minecraft.entity.Entity) ShipTransform(org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform) Vector3d(org.joml.Vector3d) IDraggable(org.valkyrienskies.mod.common.ships.entity_interaction.IDraggable) IPhysObjectWorld(org.valkyrienskies.mod.common.ships.ship_world.IPhysObjectWorld) World(net.minecraft.world.World) PhysicsObject(org.valkyrienskies.mod.common.ships.ship_world.PhysicsObject) SubscribeEvent(net.minecraftforge.fml.common.eventhandler.SubscribeEvent)

Example 2 with ShipTransform

use of org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.

the class PhysObjectRenderManager method applyRenderTransform.

private void applyRenderTransform(double partialTicks, boolean inverse) {
    Vector3dc centerOfRotation = parent.getCenterCoord();
    Entity player = Objects.requireNonNull(Minecraft.getMinecraft().getRenderViewEntity());
    double p0 = player.lastTickPosX + (player.posX - player.lastTickPosX) * partialTicks;
    double p1 = player.lastTickPosY + (player.posY - player.lastTickPosY) * partialTicks;
    double p2 = player.lastTickPosZ + (player.posZ - player.lastTickPosZ) * partialTicks;
    ShipTransform renderTransform = parent.getShipTransformationManager().getRenderTransform();
    Vector3d renderPos = renderTransform.getSubspaceToGlobal().transformPosition(centerOfRotation, new Vector3d());
    // Offset pos is used to prevent floating point errors when rendering stuff thats very far away.
    double offsetX = offsetPos.getX() - centerOfRotation.x();
    double offsetY = offsetPos.getY() - centerOfRotation.y();
    double offsetZ = offsetPos.getZ() - centerOfRotation.z();
    if (inverse) {
        AxisAngle4d rotation = new AxisAngle4d().set(renderTransform.getGlobalToSubspace());
        GL11.glTranslated(-offsetX, -offsetY, -offsetZ);
        GL11.glRotated(Math.toDegrees(rotation.angle), rotation.x, rotation.y, rotation.z);
        GL11.glTranslated(p0 - renderPos.x, p1 - renderPos.y, p2 - renderPos.z);
    } else {
        AxisAngle4d rotation = new AxisAngle4d().set(renderTransform.getSubspaceToGlobal());
        GL11.glTranslated(-p0 + renderPos.x, -p1 + renderPos.y, -p2 + renderPos.z);
        GL11.glRotated(Math.toDegrees(rotation.angle), rotation.x, rotation.y, rotation.z);
        GL11.glTranslated(offsetX, offsetY, offsetZ);
    }
}
Also used : Vector3dc(org.joml.Vector3dc) Entity(net.minecraft.entity.Entity) ShipTransform(org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform) Vector3d(org.joml.Vector3d) AxisAngle4d(org.joml.AxisAngle4d)

Example 3 with ShipTransform

use of org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.

the class WaterForcesTask method call.

/**
 * Computes the force and torque resulting from the water collisions handled by this task.
 */
@Override
public Void call() {
    final BlockPos.MutableBlockPos currentPos = new BlockPos.MutableBlockPos();
    final ShipTransform physicsTransform = parent.getShipTransformationManager().getCurrentPhysicsTransform();
    final PhysicsCalculations physicsEngine = parent.getPhysicsCalculations();
    // Vector objects reused in this method.
    final Vector3d temp0 = new Vector3d();
    final Vector3d temp1 = new Vector3d();
    final Vector3d temp2 = new Vector3d();
    final Vector3d temp3 = new Vector3d();
    final Vector3d temp4 = new Vector3d();
    final Vector3d temp5 = new Vector3d();
    final Vector3d temp6 = new Vector3d();
    final Vector3d temp7 = new Vector3d();
    final Vector3d temp8 = new Vector3d();
    final Vector3d temp9 = new Vector3d();
    for (int index = minHitIndex; index <= maxHitIndex; index++) {
        final int waterHitPosHash = waterHitsToCheck.get(index);
        SpatialDetector.setPosWithRespectTo(waterHitPosHash, colliderCenter, currentPos);
        final Vector3dc waterPosInShipSpace = physicsTransform.transformPositionNew(JOML.convertDouble(currentPos, temp0).add(.5, .5, .5), TransformType.GLOBAL_TO_SUBSPACE);
        final int minX = (int) Math.floor(waterPosInShipSpace.x() - .5);
        final int minY = (int) Math.floor(waterPosInShipSpace.y() - .5);
        final int minZ = (int) Math.floor(waterPosInShipSpace.z() - .5);
        final int maxX = (int) Math.ceil(waterPosInShipSpace.x() + .5);
        final int maxY = (int) Math.ceil(waterPosInShipSpace.y() + .5);
        final int maxZ = (int) Math.ceil(waterPosInShipSpace.z() + .5);
        final Vector3dc waterPosInWorld = JOML.convertDouble(currentPos, temp1).add(.5, .5, .5);
        for (int x = minX; x <= maxX; x++) {
            for (int z = minZ; z <= maxZ; z++) {
                final Chunk chunk = parent.getChunkClaim().containsChunk(x >> 4, z >> 4) ? parent.getChunkAt(x >> 4, z >> 4) : null;
                if (chunk == null)
                    continue;
                for (int y = minY; y <= maxY; y++) {
                    final ExtendedBlockStorage blockStorage = chunk.storageArrays[y >> 4];
                    if (blockStorage != null) {
                        final IBitOctree terrainOctree = ((ITerrainOctreeProvider) blockStorage.data).getSolidOctree();
                        if (terrainOctree.get(x & 15, y & 15, z & 15)) {
                            // Assume both the water block and terrain block are spheres, then compute the volume
                            // that overlaps
                            final Vector3dc shipSolidBlockPosInWorld = physicsTransform.transformPositionNew(temp2.set(x + .5, y + .5, z + .5), TransformType.SUBSPACE_TO_GLOBAL);
                            final double volumeDisplaced = calculateAABBOverlap(waterPosInWorld.x() - shipSolidBlockPosInWorld.x(), waterPosInWorld.y() - shipSolidBlockPosInWorld.y(), waterPosInWorld.z() - shipSolidBlockPosInWorld.z());
                            if (volumeDisplaced <= 0) {
                                // No intersection
                                continue;
                            }
                            // Collision position is average of ship solid block pos and water pos
                            final Vector3dc collisionPosInWorld = shipSolidBlockPosInWorld.add(waterPosInWorld, temp3).mul(.5);
                            final Vector3dc buoyancyForce = temp4.set(0, volumeDisplaced * GRAVITY_ACCELERATION * MASS_OF_CUBIC_METER_OF_WATER, 0);
                            final Vector3dc collisionPosRelativeToShipCenterInWorld = temp5.set(collisionPosInWorld).sub(physicsTransform.getPosX(), physicsTransform.getPosY(), physicsTransform.getPosZ());
                            addForceAtPoint(collisionPosRelativeToShipCenterInWorld, buoyancyForce, temp7);
                            {
                                // Compute water damping force
                                final Vector3dc velocity = physicsEngine.getVelocityAtPoint(collisionPosRelativeToShipCenterInWorld, temp9);
                                if (!isVectorLengthZero(velocity)) {
                                    // TODO: This is WRONG, but it'll do for now
                                    // The distance between the water block and the solid block its pushing upwards
                                    double distance = waterPosInWorld.distance(shipSolidBlockPosInWorld);
                                    final double area = Math.PI * (SPHERE_RADIUS - (distance * .5)) * (SPHERE_RADIUS - (distance * .5));
                                    final double velocitySquared = velocity.lengthSquared();
                                    // Drag formula from https://en.wikipedia.org/wiki/Drag_(physics)
                                    final double forceMagnitude = (.5) * DENSITY_OF_WATER * velocitySquared * DRAG_COEFFICIENT_OF_WATER * area;
                                    final Vector3dc dragForce = temp6.set(velocity).normalize().mul(-forceMagnitude);
                                    addForceAtPoint(collisionPosRelativeToShipCenterInWorld, dragForce, temp8);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return null;
}
Also used : ITerrainOctreeProvider(org.valkyrienskies.mod.common.util.datastructures.ITerrainOctreeProvider) IBitOctree(org.valkyrienskies.mod.common.util.datastructures.IBitOctree) Chunk(net.minecraft.world.chunk.Chunk) ExtendedBlockStorage(net.minecraft.world.chunk.storage.ExtendedBlockStorage) Vector3dc(org.joml.Vector3dc) ShipTransform(org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform) Vector3d(org.joml.Vector3d) BlockPos(net.minecraft.util.math.BlockPos) PhysicsCalculations(org.valkyrienskies.mod.common.physics.PhysicsCalculations)

Example 4 with ShipTransform

use of org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.

the class WorldPhysicsCollider method handleActualCollision.

// Takes the collision data along all axes generated prior, and creates the
// ideal value that is to be followed
private boolean handleActualCollision(BlockPos inWorldPos, BlockPos inLocalPos, IBlockState inWorldState, IBlockState inLocalState) {
    final ShipTransform parentTransform = parent.getShipTransformationManager().getCurrentPhysicsTransform();
    final boolean isXUpSolid = isBlockInWorldSolidFast(inWorldPos.getX() + 1, inWorldPos.getY(), inWorldPos.getZ());
    final boolean isXDownSolid = isBlockInWorldSolidFast(inWorldPos.getX() - 1, inWorldPos.getY(), inWorldPos.getZ());
    final boolean isYUpSolid = isBlockInWorldSolidFast(inWorldPos.getX(), inWorldPos.getY() + 1, inWorldPos.getZ());
    final boolean isYDownSolid = isBlockInWorldSolidFast(inWorldPos.getX(), inWorldPos.getY() - 1, inWorldPos.getZ());
    final boolean isZUpSolid = isBlockInWorldSolidFast(inWorldPos.getX(), inWorldPos.getY(), inWorldPos.getZ() + 1);
    final boolean isZDownSolid = isBlockInWorldSolidFast(inWorldPos.getX(), inWorldPos.getY(), inWorldPos.getZ() - 1);
    if (isXUpSolid && isXDownSolid && isYUpSolid && isYDownSolid && isZUpSolid && isZDownSolid) {
        // Interior block, skip
        return false;
    }
    for (int i = 0; i < 8; i++) {
        final int xAxis = combinationsOfOnes[i * 3];
        final int yAxis = combinationsOfOnes[i * 3 + 1];
        final int zAxis = combinationsOfOnes[i * 3 + 2];
        // Position of the World's block in global
        final Vector3dc shipBlockInLocal = temp0.set(inLocalPos.getX() + .5 + xAxis * SPHERE_RADIUS, inLocalPos.getY() + .5 + yAxis * SPHERE_RADIUS, inLocalPos.getZ() + .5 + zAxis * SPHERE_RADIUS);
        // Position of the World's block in local
        final Vector3dc shipBlockInGlobal = parentTransform.transformPositionNew(temp1.set(shipBlockInLocal), TransformType.SUBSPACE_TO_GLOBAL);
        double xUpOffset = .5 - (shipBlockInGlobal.x() - (inWorldPos.getX() + .5)) + SPHERE_RADIUS;
        double xDownOffset = .5 - ((inWorldPos.getX() + .5) - shipBlockInGlobal.x()) + SPHERE_RADIUS;
        double yUpOffset = .5 - (shipBlockInGlobal.y() - (inWorldPos.getY() + .5)) + SPHERE_RADIUS;
        double yDownOffset = .5 - ((inWorldPos.getY() + .5) - shipBlockInGlobal.y()) + SPHERE_RADIUS;
        double zUpOffset = .5 - (shipBlockInGlobal.z() - (inWorldPos.getZ() + .5)) + SPHERE_RADIUS;
        double zDownOffset = .5 - ((inWorldPos.getZ() + .5) - shipBlockInGlobal.z()) + SPHERE_RADIUS;
        if (isXUpSolid) {
            xUpOffset = 1;
        }
        if (isXDownSolid) {
            xDownOffset = 1;
        }
        if (isYUpSolid) {
            yUpOffset = 1;
        }
        if (isYDownSolid) {
            yDownOffset = 1;
        }
        if (isZUpSolid) {
            zUpOffset = 1;
        }
        if (isZDownSolid) {
            zDownOffset = 1;
        }
        if (xUpOffset > 0 && xDownOffset > 0 && yUpOffset > 0 && yDownOffset > 0 && zUpOffset > 0 && zDownOffset > 0) {
            // Intersection
            final Vector3dc axis;
            final Vector3dc response;
            // If X and Z collision have less magnitude than this, then we only consider the Y axis.
            final double THRESHOLD = .1;
            if (Math.abs(xUpOffset) < THRESHOLD && Math.abs(xDownOffset) < THRESHOLD && Math.abs(zUpOffset) < THRESHOLD && Math.abs(zDownOffset) < THRESHOLD && (!isYUpSolid || !isYDownSolid)) {
                // Ignore other axes just use Y
                if (yUpOffset < yDownOffset) {
                    // yUpOffset is minimum
                    axis = temp2.set(0, -1, 0);
                    response = axis.mul(yUpOffset, temp3);
                } else {
                    // yDownOffset is minimum
                    axis = temp2.set(0, 1, 0);
                    response = axis.mul(yDownOffset, temp3);
                }
            } else {
                // Use the minimum overlapping axis
                if (xUpOffset < xDownOffset && xUpOffset < yUpOffset && xUpOffset < yDownOffset && xUpOffset < zUpOffset && xUpOffset < zDownOffset) {
                    // xUpOffset is minimum
                    axis = temp2.set(-1, 0, 0);
                    response = axis.mul(xUpOffset, temp3);
                } else if (xDownOffset < yUpOffset && xDownOffset < yDownOffset && xDownOffset < zUpOffset && xDownOffset < zDownOffset) {
                    // xDownOffset is minimum
                    axis = temp2.set(1, 0, 0);
                    response = axis.mul(xDownOffset, temp3);
                } else if (yUpOffset < yDownOffset && yUpOffset < zUpOffset && yUpOffset < zDownOffset) {
                    // yUpOffset is minimum
                    axis = temp2.set(0, -1, 0);
                    response = axis.mul(yUpOffset, temp3);
                } else if (yDownOffset < zUpOffset && yDownOffset < zDownOffset) {
                    // yDownOffset is minimum
                    axis = temp2.set(0, 1, 0);
                    response = axis.mul(yDownOffset, temp3);
                } else if (zUpOffset < zDownOffset) {
                    // zUpOffset is minimum
                    axis = temp2.set(0, 0, -1);
                    response = axis.mul(zUpOffset, temp3);
                } else {
                    // zDownOffset is minimum
                    axis = temp2.set(0, 0, 1);
                    response = axis.mul(zDownOffset, temp3);
                }
            }
            handleCollision(shipBlockInGlobal, axis, response, 1);
        }
    }
    return false;
}
Also used : Vector3dc(org.joml.Vector3dc) ShipTransform(org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform)

Example 5 with ShipTransform

use of org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform in project Valkyrien-Warfare-Revamped by ValkyrienWarfare.

the class EntityCollisionInjector method alterEntityMovement.

// Returns false if game should use default collision
@Nullable
public static IntermediateMovementVariableStorage alterEntityMovement(Entity entity, MoverType type, double dx, double dy, double dz) {
    final double origDx = dx;
    final double origDy = dy;
    final double origDz = dz;
    final double origPosX = entity.posX;
    final double origPosY = entity.posY;
    final double origPosZ = entity.posZ;
    boolean isLiving = entity instanceof EntityLivingBase;
    Vec3d velocity = new Vec3d(dx, dy, dz);
    Polygon playerBeforeMove = new Polygon(entity.getEntityBoundingBox());
    List<Polygon> colPolys = getCollidingPolygonsAndDoBlockCols(entity, velocity);
    PhysicsObject worldBelow = null;
    IDraggable draggable = EntityDraggable.getDraggableFromEntity(entity);
    final EntityShipMovementData lastTickEntityShipMovementData = draggable.getEntityShipMovementData();
    Vector3d total = new Vector3d();
    // Used to reset the player position after collision processing, effectively
    // using the player to integrate their velocity
    double posOffestX = 0;
    double posOffestY = 0;
    double posOffestZ = 0;
    // True IFF the player is on a ladder
    boolean isPlayerOnLadder = false;
    // region Ladder movement
    if (entity instanceof EntityLivingBase) {
        final EntityLivingBase base = (EntityLivingBase) entity;
        final List<PhysicsObject> collidingShips = ((IHasShipManager) entity.getEntityWorld()).getManager().getPhysObjectsInAABB(base.getEntityBoundingBox());
        final Iterable<Triple<PhysicsObject, BlockPos, IBlockState>> ladderCollisions = getLadderCollisions(base, collidingShips);
        // For now, just ignore the y component. I may or may not use it later.
        final float forward = ((EntityLivingBase) entity).moveForward;
        final float strafe = ((EntityLivingBase) entity).moveStrafing;
        final double f1 = Math.sin(Math.toRadians(entity.rotationYaw));
        final double f2 = Math.cos(Math.toRadians(entity.rotationYaw));
        final double intendedXVel = strafe * f2 - forward * f1;
        final double intendedYVel = 0;
        final double intendedZVel = forward * f2 + strafe * f1;
        final Vector3dc originalVelocityDirection = new Vector3d(intendedXVel, intendedYVel, intendedZVel).normalize();
        final World world = entity.world;
        final Polygon playerPolygon = new Polygon(base.getEntityBoundingBox());
        for (final Triple<PhysicsObject, BlockPos, IBlockState> ladderCollision : ladderCollisions) {
            final IBlockState ladderState = ladderCollision.getRight();
            EnumFacing ladderFacing = null;
            // For now, we only support a few blocks
            if (ladderState.getPropertyKeys().contains(BlockHorizontal.FACING)) {
                ladderFacing = ladderState.getValue(BlockHorizontal.FACING);
            }
            // We need the EnumFacing of the ladder for the code to work. If we couldn't find it then just give up :/
            if (ladderFacing != null) {
                final Vector3d ladderNormal = JOML.convertDouble(ladderFacing.getDirectionVec());
                final ShipTransform shipTransform = ladderCollision.getLeft().getShipTransform();
                // Grow the ladder BB by a small margin (makes the ladder experience better imo)
                final AxisAlignedBB ladderBB = ladderCollision.getRight().getBoundingBox(world, ladderCollision.getMiddle()).offset(ladderCollision.getMiddle()).grow(.4);
                final Polygon ladderPoly = new Polygon(ladderBB, shipTransform.getSubspaceToGlobal());
                // Determine if the player is actually colliding with the ladder
                final PhysPolygonCollider collider = new PhysPolygonCollider(playerPolygon, ladderPoly, ladderCollision.getLeft().getShipTransformationManager().normals);
                collider.processData();
                shipTransform.transformDirection(ladderNormal, TransformType.SUBSPACE_TO_GLOBAL);
                // Don't use "floor ladders"
                final boolean isLadderFacingDown = ladderNormal.y > .8;
                if (isLadderFacingDown) {
                    continue;
                }
                // If the ladder is facing up, then let the player use them like monkey bars
                final boolean isLadderFacingUp = ladderNormal.y < -.8;
                // Whether or not the player is actually colliding with a ladder, since it is close to one we give the player ladder movement.
                dx = MathHelper.clamp(dx, -.15, .15);
                dz = MathHelper.clamp(dz, -.15, .15);
                base.fallDistance = 0;
                if (!isLadderFacingUp) {
                    // Use ladders like normal
                    if (dy < -.15) {
                        dy = -.15;
                    }
                    final boolean isPlayerGoingTowardsLadder = originalVelocityDirection.dot(ladderNormal) < -.1;
                    final boolean isPlayerSneakingOnLadder = base.isSneaking() && base instanceof EntityPlayer;
                    if (isPlayerSneakingOnLadder && dy < 0) {
                        dy = 0;
                    }
                    if (!collider.seperated && isPlayerGoingTowardsLadder) {
                        dy = .2;
                    }
                } else {
                    // Use ladders like monkey bars
                    dy = .2;
                }
                worldBelow = ladderCollision.getLeft();
                isPlayerOnLadder = true;
                break;
            }
        }
    }
    // endregion
    final Vector3dc velVec = new Vector3d(dx, dy, dz);
    for (Polygon poly : colPolys) {
        if (poly instanceof ShipPolygon) {
            ShipPolygon shipPoly = (ShipPolygon) poly;
            try {
                EntityPolygonCollider fast = new EntityPolygonCollider(playerBeforeMove, shipPoly, shipPoly.normals, velVec.add(total, new Vector3d()));
                if (!fast.arePolygonsSeparated()) {
                    // fastCollisions.add(fast);
                    worldBelow = shipPoly.shipFrom;
                    Vector3d response = fast.getCollisions()[fast.getMinDistanceIndex()].getResponse();
                    // TODO: Add more potential yResponses
                    double stepSquared = entity.stepHeight * entity.stepHeight;
                    // Do not do stair stepping if the player is on a ladder.
                    boolean isStep = isLiving && entity.onGround && !isPlayerOnLadder;
                    if (response.y >= 0 && VSMath.canStandOnNormal(fast.getCollisionAxes()[fast.getMinDistanceIndex()])) {
                        Vector3d slowButStopped = new Vector3d(0, -fast.getCollisions()[fast.getMinDistanceIndex()].getCollisionPenetrationDistance() / fast.getCollisionAxes()[fast.getMinDistanceIndex()].y(), 0);
                        response = slowButStopped;
                    }
                    if (isStep) {
                        EntityLivingBase living = (EntityLivingBase) entity;
                        if (Math.abs(living.moveForward) > .01 || Math.abs(living.moveStrafing) > .01) {
                            for (int i = 3; i < 6; i++) {
                                Vector3d tempResponse = fast.getCollisions()[i].getResponse();
                                if (tempResponse.y > 0 && VSMath.canStandOnNormal(fast.getCollisions()[i].getCollisionNormal()) && tempResponse.lengthSquared() < stepSquared) {
                                    if (tempResponse.lengthSquared() < .1) {
                                        // Too small to be a real step, let it through
                                        response = tempResponse;
                                    } else {
                                        // System.out.println("Try Stepping!");
                                        AxisAlignedBB axisalignedbb = entity.getEntityBoundingBox().offset(tempResponse.x, tempResponse.y, tempResponse.z);
                                        // Don't allow the player to step if the step will put them in another polygon.
                                        boolean collidesWithAnything = false;
                                        {
                                            final AxisAlignedBB newEntityBBShrunk = axisalignedbb.shrink(.15);
                                            final Polygon newEntityBBShrunkPolygon = new Polygon(newEntityBBShrunk);
                                            for (Polygon potentialStepCollision : colPolys) {
                                                if (potentialStepCollision == poly) {
                                                    // Don't run this on ourself
                                                    continue;
                                                }
                                                if (potentialStepCollision.getEnclosedAABB().intersects(newEntityBBShrunk)) {
                                                    // Finer check
                                                    ShipPolygon potentialStepCollisionShipPoly = (ShipPolygon) potentialStepCollision;
                                                    final EntityPolygonCollider checkIfStepCollidesWithBlock = new EntityPolygonCollider(newEntityBBShrunkPolygon, potentialStepCollisionShipPoly, potentialStepCollisionShipPoly.normals, new Vector3d());
                                                    checkIfStepCollidesWithBlock.processData();
                                                    if (!checkIfStepCollidesWithBlock.arePolygonsSeparated()) {
                                                        collidesWithAnything = true;
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        if (!collidesWithAnything) {
                                            entity.setEntityBoundingBox(axisalignedbb);
                                            // I think this correct, but it may create more problems than it solves
                                            response.zero();
                                            entity.resetPositionToBB();
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // total.add(response);
                    if (Math.abs(response.x) > .01D) {
                        total.x += response.x;
                    }
                    if (Math.abs(response.y) > .01D) {
                        total.y += response.y;
                    }
                    if (Math.abs(response.z) > .01D) {
                        total.z += response.z;
                    }
                    entity.posX += response.x;
                    entity.posY += response.y;
                    entity.posZ += response.z;
                    posOffestX += response.x;
                    posOffestY += response.y;
                    posOffestZ += response.z;
                    AxisAlignedBB axisalignedbb = entity.getEntityBoundingBox().offset(response.x, response.y, response.z);
                    entity.setEntityBoundingBox(axisalignedbb);
                    entity.resetPositionToBB();
                }
            } catch (Exception e) {
            // Do nothing
            }
        }
    }
    AxisAlignedBB axisalignedbb = entity.getEntityBoundingBox().offset(-posOffestX, -posOffestY, -posOffestZ);
    entity.setEntityBoundingBox(axisalignedbb);
    entity.resetPositionToBB();
    // We are on the ship that we are riding
    if (entity.ridingEntity instanceof EntityMountable) {
        final EntityMountable entityMountable = (EntityMountable) entity.ridingEntity;
        if (entityMountable.getReferencePosOptional().isPresent()) {
            final Optional<PhysicsObject> physicsObjectOptional = ValkyrienUtils.getPhysoManagingBlock(entity.world, entityMountable.getReferencePosOptional().get());
            if (physicsObjectOptional.isPresent()) {
                worldBelow = physicsObjectOptional.get();
            }
        }
    }
    if (worldBelow == null) {
        return null;
    }
    dx += total.x;
    dy += total.y;
    dz += total.z;
    boolean alreadyOnGround = entity.onGround && (dy == origDy) && origDy < 0;
    Vector3d original = new Vector3d(origDx, origDy, origDz);
    Vector3d newMov = new Vector3d(dx - origDx, dy - origDy, dz - origDz);
    entity.collidedHorizontally = original.dot(newMov) < 0;
    entity.collidedVertically = isDifSignificant(dy, origDy);
    entity.onGround = entity.collidedVertically && origDy < 0 || alreadyOnGround;
    entity.collided = entity.collidedHorizontally || entity.collidedVertically;
    // entity.resetPositionToBB();
    double motionYBefore = entity.motionY;
    float oldFallDistance = entity.fallDistance;
    Vector3d dxyz = new Vector3d(dx, dy, dz);
    ;
    Vector3d origDxyz = new Vector3d(origDx, origDy, origDz);
    Vector3d origPosXyz = new Vector3d(origPosX, origPosY, origPosZ);
    return new IntermediateMovementVariableStorage(dxyz, origDxyz, origPosXyz, alreadyOnGround, motionYBefore, oldFallDistance, worldBelow.getShipData());
}
Also used : EntityShipMovementData(org.valkyrienskies.mod.common.entity.EntityShipMovementData) AxisAlignedBB(net.minecraft.util.math.AxisAlignedBB) EnumFacing(net.minecraft.util.EnumFacing) EntityMountable(org.valkyrienskies.mod.common.entity.EntityMountable) World(net.minecraft.world.World) BlockPos(net.minecraft.util.math.BlockPos) Polygon(org.valkyrienskies.mod.common.collision.Polygon) ShipPolygon(org.valkyrienskies.mod.common.collision.ShipPolygon) IBlockState(net.minecraft.block.state.IBlockState) ShipPolygon(org.valkyrienskies.mod.common.collision.ShipPolygon) PhysicsObject(org.valkyrienskies.mod.common.ships.ship_world.PhysicsObject) EntityPolygonCollider(org.valkyrienskies.mod.common.collision.EntityPolygonCollider) Vec3d(net.minecraft.util.math.Vec3d) Triple(org.apache.commons.lang3.tuple.Triple) Vector3dc(org.joml.Vector3dc) Vector3d(org.joml.Vector3d) ShipTransform(org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform) EntityLivingBase(net.minecraft.entity.EntityLivingBase) EntityPlayer(net.minecraft.entity.player.EntityPlayer) PhysPolygonCollider(org.valkyrienskies.mod.common.collision.PhysPolygonCollider) Nullable(javax.annotation.Nullable)

Aggregations

ShipTransform (org.valkyrienskies.mod.common.ships.ship_transform.ShipTransform)32 Vector3d (org.joml.Vector3d)18 Vector3dc (org.joml.Vector3dc)15 PhysicsObject (org.valkyrienskies.mod.common.ships.ship_world.PhysicsObject)9 AxisAlignedBB (net.minecraft.util.math.AxisAlignedBB)7 World (net.minecraft.world.World)7 ShipData (org.valkyrienskies.mod.common.ships.ShipData)6 UUID (java.util.UUID)4 Nullable (javax.annotation.Nullable)4 BlockPos (net.minecraft.util.math.BlockPos)4 Vec3d (net.minecraft.util.math.Vec3d)4 IPhysObjectWorld (org.valkyrienskies.mod.common.ships.ship_world.IPhysObjectWorld)4 IBlockState (net.minecraft.block.state.IBlockState)3 Entity (net.minecraft.entity.Entity)3 Chunk (net.minecraft.world.chunk.Chunk)3 EntityShipMovementData (org.valkyrienskies.mod.common.entity.EntityShipMovementData)3 DecimalFormat (java.text.DecimalFormat)2 EntityLivingBase (net.minecraft.entity.EntityLivingBase)2 ChunkPos (net.minecraft.util.math.ChunkPos)2 ExtendedBlockStorage (net.minecraft.world.chunk.storage.ExtendedBlockStorage)2